mirror of
https://github.com/lantean-code/qbtmud.git
synced 2025-11-01 20:43:36 +00:00
Fix filter crash on files and add local storage for column sorts and filter nav
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
using Microsoft.AspNetCore.Components.Rendering;
|
using Microsoft.AspNetCore.Components.Rendering;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Runtime.ExceptionServices;
|
||||||
|
|
||||||
namespace Lantean.QBTMudBlade.Components
|
namespace Lantean.QBTMudBlade.Components
|
||||||
{
|
{
|
||||||
@@ -13,10 +14,18 @@ namespace Lantean.QBTMudBlade.Components
|
|||||||
[Parameter]
|
[Parameter]
|
||||||
public EventCallback OnClear { get; set; }
|
public EventCallback OnClear { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public bool Disabled { get; set; }
|
||||||
|
|
||||||
protected override Task OnErrorAsync(Exception exception)
|
protected override Task OnErrorAsync(Exception exception)
|
||||||
{
|
{
|
||||||
_exceptions.Add(exception);
|
_exceptions.Add(exception);
|
||||||
|
|
||||||
|
if (Disabled)
|
||||||
|
{
|
||||||
|
ExceptionDispatchInfo.Capture(exception).Throw();
|
||||||
|
}
|
||||||
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,8 @@
|
|||||||
OnRowClick="RowClick"
|
OnRowClick="RowClick"
|
||||||
RowStyleFunc="RowStyle"
|
RowStyleFunc="RowStyle"
|
||||||
RowClassFunc="RowClass"
|
RowClassFunc="RowClass"
|
||||||
AllowUnsorted="false">
|
AllowUnsorted="false"
|
||||||
|
Virtualize="true">
|
||||||
<ColGroup>
|
<ColGroup>
|
||||||
<col style="width: 30px" />
|
<col style="width: 30px" />
|
||||||
@foreach (var column in GetColumns())
|
@foreach (var column in GetColumns())
|
||||||
@@ -41,7 +42,7 @@
|
|||||||
<MudTh>
|
<MudTh>
|
||||||
@if (column.SortSelector is not null)
|
@if (column.SortSelector is not null)
|
||||||
{
|
{
|
||||||
<MudTableSortLabel T="Torrent" SortDirectionChanged="@(c => SetSort(column.SortSelector, c))" InitialDirection="column.InitialDirection">@column.Header</MudTableSortLabel>
|
<MudTableSortLabel T="ContentItem" SortDirectionChanged="@(c => SetSort(column.Id, c))" InitialDirection="column.InitialDirection">@column.Header</MudTableSortLabel>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -16,14 +16,15 @@ namespace Lantean.QBTMudBlade.Components
|
|||||||
{
|
{
|
||||||
private readonly bool _refreshEnabled = true;
|
private readonly bool _refreshEnabled = true;
|
||||||
|
|
||||||
private const string _columnStorageKey = "FilesTab.Columns";
|
private const string _columnSelectionStorageKey = "FilesTab.ColumnSelection";
|
||||||
|
private const string _columnSortStorageKey = "FilesTab.ColumnSort";
|
||||||
|
|
||||||
private readonly CancellationTokenSource _timerCancellationToken = new();
|
private readonly CancellationTokenSource _timerCancellationToken = new();
|
||||||
private bool _disposedValue;
|
private bool _disposedValue;
|
||||||
|
|
||||||
private Func<ContentItem, object?> SortSelector { get; set; } = c => c.Name;
|
private string? _sortColumn;
|
||||||
|
|
||||||
private SortDirection SortDirection { get; set; } = SortDirection.Ascending;
|
private SortDirection _sortDirection = SortDirection.Ascending;
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public bool Active { get; set; }
|
public bool Active { get; set; }
|
||||||
@@ -55,6 +56,7 @@ namespace Lantean.QBTMudBlade.Components
|
|||||||
protected HashSet<ContentItem> SelectedItems { get; set; } = [];
|
protected HashSet<ContentItem> SelectedItems { get; set; } = [];
|
||||||
|
|
||||||
protected List<ColumnDefinition<ContentItem>> _columns = [];
|
protected List<ColumnDefinition<ContentItem>> _columns = [];
|
||||||
|
private List<PropertyFilterDefinition<ContentItem>>? _filterDefinitions;
|
||||||
|
|
||||||
protected ContentItem? SelectedItem { get; set; }
|
protected ContentItem? SelectedItem { get; set; }
|
||||||
|
|
||||||
@@ -80,18 +82,18 @@ namespace Lantean.QBTMudBlade.Components
|
|||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
if (!await LocalStorage.ContainKeyAsync(_columnStorageKey))
|
var selectedColumns = await LocalStorage.GetItemAsync<HashSet<string>>(_columnSelectionStorageKey);
|
||||||
|
if (selectedColumns is not null)
|
||||||
{
|
{
|
||||||
return;
|
SelectedColumns = selectedColumns;
|
||||||
}
|
}
|
||||||
|
|
||||||
var selectedColumns = await LocalStorage.GetItemAsync<HashSet<string>>(_columnStorageKey);
|
var columnSort = await LocalStorage.GetItemAsync<Tuple<string, SortDirection>>(_columnSortStorageKey);
|
||||||
if (selectedColumns is null)
|
if (columnSort is not null)
|
||||||
{
|
{
|
||||||
return;
|
_sortColumn = columnSort.Item1;
|
||||||
|
_sortDirection = columnSort.Item2;
|
||||||
}
|
}
|
||||||
|
|
||||||
SelectedColumns = selectedColumns;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected IEnumerable<ColumnDefinition<ContentItem>> GetColumns()
|
protected IEnumerable<ColumnDefinition<ContentItem>> GetColumns()
|
||||||
@@ -116,14 +118,14 @@ namespace Lantean.QBTMudBlade.Components
|
|||||||
|
|
||||||
SelectedColumns = (HashSet<string>)result.Data;
|
SelectedColumns = (HashSet<string>)result.Data;
|
||||||
|
|
||||||
await LocalStorage.SetItemAsync(_columnStorageKey, SelectedColumns);
|
await LocalStorage.SetItemAsync(_columnSelectionStorageKey, SelectedColumns);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async Task ShowFilterDialog()
|
protected async Task ShowFilterDialog()
|
||||||
{
|
{
|
||||||
var parameters = new DialogParameters
|
var parameters = new DialogParameters
|
||||||
{
|
{
|
||||||
{ nameof(FilterOptionsDialog<ContentItem>.FilterDefinitions), Filters },
|
{ nameof(FilterOptionsDialog<ContentItem>.FilterDefinitions), _filterDefinitions },
|
||||||
};
|
};
|
||||||
|
|
||||||
var result = await DialogService.ShowAsync<FilterOptionsDialog<ContentItem>>("Filters", parameters, DialogHelper.FormDialogOptions);
|
var result = await DialogService.ShowAsync<FilterOptionsDialog<ContentItem>>("Filters", parameters, DialogHelper.FormDialogOptions);
|
||||||
@@ -134,14 +136,15 @@ namespace Lantean.QBTMudBlade.Components
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var filterDefinitions = (List<PropertyFilterDefinition<ContentItem>>?)dialogResult.Data;
|
_filterDefinitions = (List<PropertyFilterDefinition<ContentItem>>?)dialogResult.Data;
|
||||||
if (filterDefinitions is null)
|
if (_filterDefinitions is null)
|
||||||
{
|
{
|
||||||
|
Filters = null;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var filters = new List<Func<ContentItem, bool>>();
|
var filters = new List<Func<ContentItem, bool>>();
|
||||||
foreach (var filterDefinition in filterDefinitions)
|
foreach (var filterDefinition in _filterDefinitions)
|
||||||
{
|
{
|
||||||
var expression = Filter.FilterExpressionGenerator.GenerateExpression(filterDefinition, false);
|
var expression = Filter.FilterExpressionGenerator.GenerateExpression(filterDefinition, false);
|
||||||
filters.Add(expression.Compile());
|
filters.Add(expression.Compile());
|
||||||
@@ -154,6 +157,11 @@ namespace Lantean.QBTMudBlade.Components
|
|||||||
{
|
{
|
||||||
Filters = null;
|
Filters = null;
|
||||||
await InvokeAsync(StateHasChanged);
|
await InvokeAsync(StateHasChanged);
|
||||||
|
if (FileList is null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SelectedItems = FileList.Values.Where(f => f.Priority != Priority.DoNotDownload).ToHashSet();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async ValueTask DisposeAsync()
|
public async ValueTask DisposeAsync()
|
||||||
@@ -378,10 +386,12 @@ namespace Lantean.QBTMudBlade.Components
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetSort(Func<ContentItem, object?> sortSelector, SortDirection sortDirection)
|
private async Task SetSort(string columnId, SortDirection sortDirection)
|
||||||
{
|
{
|
||||||
SortSelector = sortSelector;
|
_sortColumn = columnId;
|
||||||
SortDirection = sortDirection;
|
_sortDirection = sortDirection;
|
||||||
|
|
||||||
|
await LocalStorage.SetItemAsync(_columnSortStorageKey, new Tuple<string, SortDirection>(columnId, sortDirection));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void ToggleNode(ContentItem contentItem, MouseEventArgs args)
|
protected void ToggleNode(ContentItem contentItem, MouseEventArgs args)
|
||||||
@@ -411,11 +421,19 @@ namespace Lantean.QBTMudBlade.Components
|
|||||||
return Files.Where(f => f.Name.StartsWith(contentItem.Name + Extensions.DirectorySeparator) && !f.IsFolder);
|
return Files.Where(f => f.Name.StartsWith(contentItem.Name + Extensions.DirectorySeparator) && !f.IsFolder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Func<ContentItem, object?> GetSortSelector()
|
||||||
|
{
|
||||||
|
var sortSelector = _columns.Find(c => c.Id == _sortColumn)?.SortSelector;
|
||||||
|
|
||||||
|
return sortSelector ?? (i => i.Name);
|
||||||
|
}
|
||||||
|
|
||||||
private IEnumerable<ContentItem> GetDescendants(ContentItem folder, int level)
|
private IEnumerable<ContentItem> GetDescendants(ContentItem folder, int level)
|
||||||
{
|
{
|
||||||
level++;
|
level++;
|
||||||
var descendantsKey = folder.GetDescendantsKey(level);
|
var descendantsKey = folder.GetDescendantsKey(level);
|
||||||
foreach (var item in FileList!.Values.Where(f => f.Name.StartsWith(descendantsKey)).OrderByDirection(SortDirection, SortSelector))
|
|
||||||
|
foreach (var item in FileList!.Values.Where(f => f.Name.StartsWith(descendantsKey)).OrderByDirection(_sortDirection, GetSortSelector()))
|
||||||
{
|
{
|
||||||
if (item.IsFolder)
|
if (item.IsFolder)
|
||||||
{
|
{
|
||||||
@@ -474,12 +492,12 @@ namespace Lantean.QBTMudBlade.Components
|
|||||||
// this is a flat file structure
|
// this is a flat file structure
|
||||||
if (maxLevel == 0)
|
if (maxLevel == 0)
|
||||||
{
|
{
|
||||||
return FileList.Values.Where(FilterContentItem).OrderByDirection(SortDirection, SortSelector).ToList().AsReadOnly();
|
return FileList.Values.Where(FilterContentItem).OrderByDirection(_sortDirection, GetSortSelector()).ToList().AsReadOnly();
|
||||||
}
|
}
|
||||||
|
|
||||||
var list = new List<ContentItem>();
|
var list = new List<ContentItem>();
|
||||||
|
|
||||||
var folders = FileList.Values.Where(c => c.IsFolder && c.Level == 0).OrderByDirection(SortDirection, SortSelector).ToList();
|
var folders = FileList.Values.Where(c => c.IsFolder && c.Level == 0).OrderByDirection(_sortDirection, GetSortSelector()).ToList();
|
||||||
foreach (var folder in folders)
|
foreach (var folder in folders)
|
||||||
{
|
{
|
||||||
list.Add(folder);
|
list.Add(folder);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Lantean.QBTMudBlade.Models;
|
using Blazored.LocalStorage;
|
||||||
|
using Lantean.QBTMudBlade.Models;
|
||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
using MudBlazor;
|
using MudBlazor;
|
||||||
|
|
||||||
@@ -6,6 +7,11 @@ namespace Lantean.QBTMudBlade.Components
|
|||||||
{
|
{
|
||||||
public partial class FiltersNav
|
public partial class FiltersNav
|
||||||
{
|
{
|
||||||
|
private const string _statusSelectionStorageKey = "FiltersNav.Selection.Status";
|
||||||
|
private const string _categorySelectionStorageKey = "FiltersNav.Selection.Category";
|
||||||
|
private const string _tagSelectionStorageKey = "FiltersNav.Selection.Tag";
|
||||||
|
private const string _trackerSelectionStorageKey = "FiltersNav.Selection.Tracker";
|
||||||
|
|
||||||
private bool _statusExpanded = true;
|
private bool _statusExpanded = true;
|
||||||
private bool _categoriesExpanded = true;
|
private bool _categoriesExpanded = true;
|
||||||
private bool _tagsExpanded = true;
|
private bool _tagsExpanded = true;
|
||||||
@@ -19,6 +25,9 @@ namespace Lantean.QBTMudBlade.Components
|
|||||||
|
|
||||||
protected string Tracker { get; set; } = FilterHelper.TRACKER_ALL;
|
protected string Tracker { get; set; } = FilterHelper.TRACKER_ALL;
|
||||||
|
|
||||||
|
[Inject]
|
||||||
|
public ILocalStorageService LocalStorage { get; set; } = default!;
|
||||||
|
|
||||||
[CascadingParameter]
|
[CascadingParameter]
|
||||||
public MainData? MainData { get; set; }
|
public MainData? MainData { get; set; }
|
||||||
|
|
||||||
@@ -42,28 +51,55 @@ namespace Lantean.QBTMudBlade.Components
|
|||||||
|
|
||||||
public Dictionary<string, int> Statuses => MainData?.StatusState.ToDictionary(d => d.Key, d => d.Value.Count) ?? [];
|
public Dictionary<string, int> Statuses => MainData?.StatusState.ToDictionary(d => d.Key, d => d.Value.Count) ?? [];
|
||||||
|
|
||||||
|
protected override async Task OnInitializedAsync()
|
||||||
|
{
|
||||||
|
if (await LocalStorage.ContainKeyAsync(_statusSelectionStorageKey))
|
||||||
|
{
|
||||||
|
Status = await LocalStorage.GetItemAsStringAsync(_statusSelectionStorageKey) ?? Models.Status.All.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (await LocalStorage.ContainKeyAsync(_categorySelectionStorageKey))
|
||||||
|
{
|
||||||
|
Category = await LocalStorage.GetItemAsStringAsync(_categorySelectionStorageKey) ?? FilterHelper.CATEGORY_ALL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (await LocalStorage.ContainKeyAsync(_tagSelectionStorageKey))
|
||||||
|
{
|
||||||
|
Tag = await LocalStorage.GetItemAsStringAsync(_tagSelectionStorageKey) ?? FilterHelper.TAG_ALL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (await LocalStorage.ContainKeyAsync(_trackerSelectionStorageKey))
|
||||||
|
{
|
||||||
|
Tracker = await LocalStorage.GetItemAsStringAsync(_trackerSelectionStorageKey) ?? FilterHelper.TRACKER_ALL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected async Task StatusValueChanged(string value)
|
protected async Task StatusValueChanged(string value)
|
||||||
{
|
{
|
||||||
Status = value;
|
Status = value;
|
||||||
await StatusChanged.InvokeAsync(Enum.Parse<Status>(value));
|
await StatusChanged.InvokeAsync(Enum.Parse<Status>(value));
|
||||||
|
await LocalStorage.SetItemAsStringAsync(_statusSelectionStorageKey, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async Task CategoryValueChanged(string value)
|
protected async Task CategoryValueChanged(string value)
|
||||||
{
|
{
|
||||||
Category = value;
|
Category = value;
|
||||||
await CategoryChanged.InvokeAsync(value);
|
await CategoryChanged.InvokeAsync(value);
|
||||||
|
await LocalStorage.SetItemAsStringAsync(_categorySelectionStorageKey, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async Task TagValueChanged(string value)
|
protected async Task TagValueChanged(string value)
|
||||||
{
|
{
|
||||||
Tag = value;
|
Tag = value;
|
||||||
await TagChanged.InvokeAsync(value);
|
await TagChanged.InvokeAsync(value);
|
||||||
|
await LocalStorage.SetItemAsStringAsync(_tagSelectionStorageKey, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async Task TrackerValueChanged(string value)
|
protected async Task TrackerValueChanged(string value)
|
||||||
{
|
{
|
||||||
Tracker = value;
|
Tracker = value;
|
||||||
await TrackerChanged.InvokeAsync(value);
|
await TrackerChanged.InvokeAsync(value);
|
||||||
|
await LocalStorage.SetItemAsStringAsync(_trackerSelectionStorageKey, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static string GetHostName(string tracker)
|
protected static string GetHostName(string tracker)
|
||||||
@@ -78,7 +114,5 @@ namespace Lantean.QBTMudBlade.Components
|
|||||||
return tracker;
|
return tracker;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -28,6 +28,11 @@ namespace Lantean.QBTMudBlade
|
|||||||
return "∞";
|
return "∞";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (seconds < 60)
|
||||||
|
{
|
||||||
|
return "< 1m";
|
||||||
|
}
|
||||||
|
|
||||||
var time = TimeSpan.FromSeconds(seconds.Value);
|
var time = TimeSpan.FromSeconds(seconds.Value);
|
||||||
var sb = new StringBuilder();
|
var sb = new StringBuilder();
|
||||||
if (prefix is not null)
|
if (prefix is not null)
|
||||||
@@ -85,6 +90,11 @@ namespace Lantean.QBTMudBlade
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (size < 0)
|
||||||
|
{
|
||||||
|
size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
var stringBuilder = new StringBuilder();
|
var stringBuilder = new StringBuilder();
|
||||||
if (prefix is not null)
|
if (prefix is not null)
|
||||||
{
|
{
|
||||||
@@ -275,6 +285,11 @@ namespace Lantean.QBTMudBlade
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (value < 0)
|
||||||
|
{
|
||||||
|
value = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (value == 0)
|
if (value == 0)
|
||||||
{
|
{
|
||||||
return "0%";
|
return "0%";
|
||||||
|
|||||||
@@ -30,17 +30,17 @@ namespace Lantean.QBTMudBlade.Filter
|
|||||||
return filter.Operator switch
|
return filter.Operator switch
|
||||||
{
|
{
|
||||||
FilterOperator.String.Contains =>
|
FilterOperator.String.Contains =>
|
||||||
propertyExpression.Modify<T>((Expression<Func<string?, bool>>)(x => x != null && value != null && x.Contains(value, stringComparer))),
|
propertyExpression.Modify<T>((Expression<Func<object?, bool>>)(x => (string?)x != null && value != null && ((string)x).Contains(value, stringComparer))),
|
||||||
FilterOperator.String.NotContains =>
|
FilterOperator.String.NotContains =>
|
||||||
propertyExpression.Modify<T>((Expression<Func<string?, bool>>)(x => x != null && value != null && !x.Contains(value, stringComparer))),
|
propertyExpression.Modify<T>((Expression<Func<object?, bool>>)(x => (string?)x != null && value != null && !((string)x).Contains(value, stringComparer))),
|
||||||
FilterOperator.String.Equal =>
|
FilterOperator.String.Equal =>
|
||||||
propertyExpression.Modify<T>((Expression<Func<string?, bool>>)(x => x != null && x.Equals(value, stringComparer))),
|
propertyExpression.Modify<T>((Expression<Func<object?, bool>>)(x => (string?)x != null && ((string)x).Equals(value, stringComparer))),
|
||||||
FilterOperator.String.NotEqual =>
|
FilterOperator.String.NotEqual =>
|
||||||
propertyExpression.Modify<T>((Expression<Func<string?, bool>>)(x => x != null && !x.Equals(value, stringComparer))),
|
propertyExpression.Modify<T>((Expression<Func<object?, bool>>)(x => (string?)x != null && !((string)x).Equals(value, stringComparer))),
|
||||||
FilterOperator.String.StartsWith =>
|
FilterOperator.String.StartsWith =>
|
||||||
propertyExpression.Modify<T>((Expression<Func<string?, bool>>)(x => x != null && value != null && x.StartsWith(value, stringComparer))),
|
propertyExpression.Modify<T>((Expression<Func<object?, bool>>)(x => (string?)x != null && value != null && ((string)x).StartsWith(value, stringComparer))),
|
||||||
FilterOperator.String.EndsWith =>
|
FilterOperator.String.EndsWith =>
|
||||||
propertyExpression.Modify<T>((Expression<Func<string?, bool>>)(x => x != null && value != null && x.EndsWith(value, stringComparer))),
|
propertyExpression.Modify<T>((Expression<Func<object?, bool>>)(x => (string?)x != null && value != null && ((string)x).EndsWith(value, stringComparer))),
|
||||||
FilterOperator.String.Empty => propertyExpression.Modify<T>((Expression<Func<string?, bool>>)(x => string.IsNullOrWhiteSpace(x))),
|
FilterOperator.String.Empty => propertyExpression.Modify<T>((Expression<Func<string?, bool>>)(x => string.IsNullOrWhiteSpace(x))),
|
||||||
FilterOperator.String.NotEmpty => propertyExpression.Modify<T>((Expression<Func<string?, bool>>)(x => !string.IsNullOrWhiteSpace(x))),
|
FilterOperator.String.NotEmpty => propertyExpression.Modify<T>((Expression<Func<string?, bool>>)(x => !string.IsNullOrWhiteSpace(x))),
|
||||||
_ => x => true
|
_ => x => true
|
||||||
|
|||||||
@@ -1,33 +1,36 @@
|
|||||||
@inherits LayoutComponentBase
|
@inherits LayoutComponentBase
|
||||||
|
|
||||||
|
|
||||||
<EnhancedErrorBoundary @ref="ErrorBoundary" OnClear="Cleared">
|
<EnhancedErrorBoundary @ref="ErrorBoundary" OnClear="Cleared">
|
||||||
<MudThemeProvider />
|
|
||||||
<MudDialogProvider />
|
</EnhancedErrorBoundary>
|
||||||
<MudSnackbarProvider />
|
|
||||||
|
|
||||||
<PageTitle>qBittorrent Web UI</PageTitle>
|
<MudThemeProvider />
|
||||||
|
<MudDialogProvider />
|
||||||
|
<MudSnackbarProvider />
|
||||||
|
|
||||||
<MudLayout>
|
<PageTitle>qBittorrent Web UI</PageTitle>
|
||||||
<MudAppBar Elevation="1">
|
|
||||||
<MudIconButton Icon="@Icons.Material.Filled.Menu" Color="Color.Inherit" Edge="Edge.Start" OnClick="ToggleDrawer" />
|
<MudLayout>
|
||||||
<MudText Typo="Typo.h5" Class="ml-3">qBittorrent Web UI</MudText>
|
<MudAppBar Elevation="1">
|
||||||
<MudSpacer />
|
<MudIconButton Icon="@Icons.Material.Filled.Menu" Color="Color.Inherit" Edge="Edge.Start" OnClick="ToggleDrawer" />
|
||||||
@if (ErrorBoundary?.Errors.Count > 0)
|
<MudText Typo="Typo.h5" Class="ml-3">qBittorrent Web UI</MudText>
|
||||||
{
|
<MudSpacer />
|
||||||
<MudBadge Content="@(ErrorBoundary?.Errors.Count ?? 0)" Color="Color.Error" Overlap="true">
|
@if (ErrorBoundary?.Errors.Count > 0)
|
||||||
<MudIconButton Icon="@Icons.Material.Filled.Error" Color="Color.Default" OnClick="ToggleErrorDrawer" />
|
{
|
||||||
</MudBadge>
|
<MudBadge Content="@(ErrorBoundary?.Errors.Count ?? 0)" Color="Color.Error" Overlap="true">
|
||||||
}
|
<MudIconButton Icon="@Icons.Material.Filled.Error" Color="Color.Default" OnClick="ToggleErrorDrawer" />
|
||||||
@if (ShowMenu)
|
</MudBadge>
|
||||||
{
|
}
|
||||||
<Menu />
|
@if (ShowMenu)
|
||||||
}
|
{
|
||||||
</MudAppBar>
|
<Menu />
|
||||||
<MudDrawer Open="ErrorDrawerOpen" ClipMode="DrawerClipMode.Docked" Elevation="2" Anchor="Anchor.Right">
|
}
|
||||||
<ErrorDisplay ErrorBoundary="ErrorBoundary" />
|
</MudAppBar>
|
||||||
</MudDrawer>
|
<MudDrawer Open="ErrorDrawerOpen" ClipMode="DrawerClipMode.Docked" Elevation="2" Anchor="Anchor.Right">
|
||||||
<CascadingValue Value="DrawerOpen" Name="DrawerOpen">
|
<ErrorDisplay ErrorBoundary="ErrorBoundary" />
|
||||||
@Body
|
</MudDrawer>
|
||||||
</CascadingValue>
|
<CascadingValue Value="DrawerOpen" Name="DrawerOpen">
|
||||||
</MudLayout>
|
@Body
|
||||||
</EnhancedErrorBoundary>
|
</CascadingValue>
|
||||||
|
</MudLayout>
|
||||||
@@ -49,7 +49,7 @@ namespace Lantean.QBTMudBlade.Pages
|
|||||||
#if DEBUG
|
#if DEBUG
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
await DoLogin("admin", "a8hbfvNP2");
|
await DoLogin("admin", "pdqYws6EQ");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,7 +48,7 @@
|
|||||||
<MudTh>
|
<MudTh>
|
||||||
@if (column.SortSelector is not null)
|
@if (column.SortSelector is not null)
|
||||||
{
|
{
|
||||||
<MudTableSortLabel T="Torrent" SortDirectionChanged="@(c => SetSort(column.SortSelector, c))">@column.Header</MudTableSortLabel>
|
<MudTableSortLabel T="Torrent" SortDirectionChanged="@(c => SetSort(column.Id, c))">@column.Header</MudTableSortLabel>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -10,7 +10,8 @@ namespace Lantean.QBTMudBlade.Pages
|
|||||||
{
|
{
|
||||||
public partial class TorrentList
|
public partial class TorrentList
|
||||||
{
|
{
|
||||||
private const string _columnStorageKey = "TorrentList.Columns";
|
private const string _columnSelectionStorageKey = "TorrentList.ColumnSelection";
|
||||||
|
private const string _columnSortStorageKey = "TorrentList.ColumnSort";
|
||||||
|
|
||||||
[Inject]
|
[Inject]
|
||||||
protected IApiClient ApiClient { get; set; } = default!;
|
protected IApiClient ApiClient { get; set; } = default!;
|
||||||
@@ -45,18 +46,18 @@ namespace Lantean.QBTMudBlade.Pages
|
|||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
if (!await LocalStorage.ContainKeyAsync(_columnStorageKey))
|
var selectedColumns = await LocalStorage.GetItemAsync<HashSet<string>>(_columnSelectionStorageKey);
|
||||||
|
if (selectedColumns is not null)
|
||||||
{
|
{
|
||||||
return;
|
SelectedColumns = selectedColumns;
|
||||||
}
|
}
|
||||||
|
|
||||||
var selectedColumns = await LocalStorage.GetItemAsync<HashSet<string>>(_columnStorageKey);
|
var columnSort = await LocalStorage.GetItemAsync<Tuple<string, SortDirection>>(_columnSortStorageKey);
|
||||||
if (selectedColumns is null)
|
if (columnSort is not null)
|
||||||
{
|
{
|
||||||
return;
|
_sortColumn = columnSort.Item1;
|
||||||
|
_sortDirection = columnSort.Item2;
|
||||||
}
|
}
|
||||||
|
|
||||||
SelectedColumns = selectedColumns;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnParametersSet()
|
protected override void OnParametersSet()
|
||||||
@@ -69,7 +70,7 @@ namespace Lantean.QBTMudBlade.Pages
|
|||||||
SelectedColumns.Remove("#");
|
SelectedColumns.Remove("#");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_sortSelector ??= _columns.First(c => c.Enabled).SortSelector;
|
_sortColumn ??= _columns.First(c => c.Enabled).Id;
|
||||||
|
|
||||||
if (SelectedTorrent is not null && Torrents is not null && !Torrents.Contains(SelectedTorrent))
|
if (SelectedTorrent is not null && Torrents is not null && !Torrents.Contains(SelectedTorrent))
|
||||||
{
|
{
|
||||||
@@ -84,7 +85,9 @@ namespace Lantean.QBTMudBlade.Pages
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Torrents.OrderByDirection(_sortDirection, _sortSelector ?? (t => t.Priority));
|
var sortSelector = _columns.Find(c => c.Id == _sortColumn)?.SortSelector;
|
||||||
|
|
||||||
|
return Torrents.OrderByDirection(_sortDirection, sortSelector ?? (t => t.Priority));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void SelectedItemsChanged(HashSet<Torrent> selectedItems)
|
protected void SelectedItemsChanged(HashSet<Torrent> selectedItems)
|
||||||
@@ -214,7 +217,7 @@ namespace Lantean.QBTMudBlade.Pages
|
|||||||
|
|
||||||
SelectedColumns = (HashSet<string>)result.Data;
|
SelectedColumns = (HashSet<string>)result.Data;
|
||||||
|
|
||||||
await LocalStorage.SetItemAsync(_columnStorageKey, SelectedColumns);
|
await LocalStorage.SetItemAsync(_columnSelectionStorageKey, SelectedColumns);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void ShowTorrent()
|
protected void ShowTorrent()
|
||||||
@@ -243,10 +246,12 @@ namespace Lantean.QBTMudBlade.Pages
|
|||||||
return _columns.Where(c => SelectedColumns.Contains(c.Id));
|
return _columns.Where(c => SelectedColumns.Contains(c.Id));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetSort(Func<Torrent, object?> sortSelector, SortDirection sortDirection)
|
private async Task SetSort(string columnId, SortDirection sortDirection)
|
||||||
{
|
{
|
||||||
_sortSelector = sortSelector;
|
_sortColumn = columnId;
|
||||||
_sortDirection = sortDirection;
|
_sortDirection = sortDirection;
|
||||||
|
|
||||||
|
await LocalStorage.SetItemAsync(_columnSortStorageKey, new Tuple<string, SortDirection>(columnId, sortDirection));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected List<ColumnDefinition<Torrent>> _columns =
|
protected List<ColumnDefinition<Torrent>> _columns =
|
||||||
@@ -286,7 +291,7 @@ namespace Lantean.QBTMudBlade.Pages
|
|||||||
//CreateColumnDefinition("Reannounce In", t => t.Reannounce, enabled: false),
|
//CreateColumnDefinition("Reannounce In", t => t.Reannounce, enabled: false),
|
||||||
];
|
];
|
||||||
|
|
||||||
private Func<Torrent, object?>? _sortSelector;
|
private string? _sortColumn;
|
||||||
private SortDirection _sortDirection;
|
private SortDirection _sortDirection;
|
||||||
|
|
||||||
private static ColumnDefinition<Torrent> CreateColumnDefinition(string name, Func<Torrent, object?> selector, RenderFragment<RowContext<Torrent>> rowTemplate, int? width = null, string? tdClass = null, bool enabled = true)
|
private static ColumnDefinition<Torrent> CreateColumnDefinition(string name, Func<Torrent, object?> selector, RenderFragment<RowContext<Torrent>> rowTemplate, int? width = null, string? tdClass = null, bool enabled = true)
|
||||||
|
|||||||
Reference in New Issue
Block a user