mirror of
https://github.com/lantean-code/qbtmud.git
synced 2025-11-02 13:03:23 +00:00
Upgrade to MudBlazor 7 and add log pages
This commit is contained in:
@@ -3,15 +3,13 @@
|
|||||||
<MudGrid>
|
<MudGrid>
|
||||||
<MudItem xs="12">
|
<MudItem xs="12">
|
||||||
<MudFileUpload T="IReadOnlyList<IBrowserFile>" FilesChanged="UploadFiles" Accept=".torrent" MaximumFileCount="50" >
|
<MudFileUpload T="IReadOnlyList<IBrowserFile>" FilesChanged="UploadFiles" Accept=".torrent" MaximumFileCount="50" >
|
||||||
<ButtonTemplate>
|
<ActivatorContent>
|
||||||
<MudButton HtmlTag="label"
|
<MudButton Variant="Variant.Filled"
|
||||||
Variant="Variant.Filled"
|
|
||||||
Color="Color.Primary"
|
Color="Color.Primary"
|
||||||
StartIcon="@Icons.Material.Filled.CloudUpload"
|
StartIcon="@Icons.Material.Filled.CloudUpload">
|
||||||
for="@context.Id">
|
|
||||||
Choose files
|
Choose files
|
||||||
</MudButton>
|
</MudButton>
|
||||||
</ButtonTemplate>
|
</ActivatorContent>
|
||||||
</MudFileUpload>
|
</MudFileUpload>
|
||||||
</MudItem>
|
</MudItem>
|
||||||
</MudGrid>
|
</MudGrid>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<DialogContent>
|
<DialogContent>
|
||||||
<MudGrid>
|
<MudGrid>
|
||||||
<MudItem xs="12">
|
<MudItem xs="12">
|
||||||
<MudList Clickable="true">
|
<MudList T="string">
|
||||||
<MudListItem Icon="@Icons.Material.Filled.Add" IconColor="Color.Info" OnClick="AddCategory">Add</MudListItem>
|
<MudListItem Icon="@Icons.Material.Filled.Add" IconColor="Color.Info" OnClick="AddCategory">Add</MudListItem>
|
||||||
<MudListItem Icon="@Icons.Material.Filled.Remove" IconColor="Color.Error" OnClick="RemoveCategory">Remove</MudListItem>
|
<MudListItem Icon="@Icons.Material.Filled.Remove" IconColor="Color.Error" OnClick="RemoveCategory">Remove</MudListItem>
|
||||||
<MudDivider />
|
<MudDivider />
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<DialogContent>
|
<DialogContent>
|
||||||
<MudGrid>
|
<MudGrid>
|
||||||
<MudItem xs="12">
|
<MudItem xs="12">
|
||||||
<MudList Clickable="true">
|
<MudList T="string">
|
||||||
<MudListItem Icon="@Icons.Material.Filled.Add" IconColor="Color.Info" OnClick="AddTag">Add</MudListItem>
|
<MudListItem Icon="@Icons.Material.Filled.Add" IconColor="Color.Info" OnClick="AddTag">Add</MudListItem>
|
||||||
<MudListItem Icon="@Icons.Material.Filled.Remove" IconColor="Color.Error" OnClick="RemoveAllTags">Remove All</MudListItem>
|
<MudListItem Icon="@Icons.Material.Filled.Remove" IconColor="Color.Error" OnClick="RemoveAllTags">Remove All</MudListItem>
|
||||||
<MudDivider />
|
<MudDivider />
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
using Microsoft.AspNetCore.Components.Web;
|
using Microsoft.AspNetCore.Components.Web;
|
||||||
using MudBlazor;
|
using MudBlazor;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace Lantean.QBTMudBlade.Components.Dialogs
|
namespace Lantean.QBTMudBlade.Components.Dialogs
|
||||||
{
|
{
|
||||||
public partial class SliderFieldDialog<T>
|
public partial class SliderFieldDialog<T> where T : struct, INumber<T>
|
||||||
{
|
{
|
||||||
[CascadingParameter]
|
[CascadingParameter]
|
||||||
public MudDialogInstance MudDialog { get; set; } = default!;
|
public MudDialogInstance MudDialog { get; set; } = default!;
|
||||||
@@ -13,13 +14,13 @@ namespace Lantean.QBTMudBlade.Components.Dialogs
|
|||||||
public string Label { get; set; } = default!;
|
public string Label { get; set; } = default!;
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public T? Value { get; set; }
|
public T Value { get; set; }
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public T? Min { get; set; }
|
public T Min { get; set; } = T.Zero;
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public T? Max { get; set; }
|
public T Max { get; set; } = T.One;
|
||||||
|
|
||||||
protected void Cancel(MouseEventArgs args)
|
protected void Cancel(MouseEventArgs args)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -40,7 +40,7 @@
|
|||||||
<MudTh Class="@className" Style="@(GetColumnStyle(column))">
|
<MudTh Class="@className" Style="@(GetColumnStyle(column))">
|
||||||
@if (column.SortSelector is not null)
|
@if (column.SortSelector is not null)
|
||||||
{
|
{
|
||||||
<SortLabel SortDirectionChanged="@(c => SetSort(column.Id, c))" SortDirection="@(column.Id == _sortColumn ? _sortDirection : SortDirection.None)">@columnHeader</SortLabel>
|
<SortLabel Class="column-header" SortDirectionChanged="@(c => SetSort(column.Id, c))" SortDirection="@(column.Id == _sortColumn ? _sortDirection : SortDirection.None)">@columnHeader</SortLabel>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -190,6 +190,10 @@ namespace Lantean.QBTMudBlade.Components
|
|||||||
|
|
||||||
protected async Task OnRowClickInternal(TableRowClickEventArgs<T> eventArgs)
|
protected async Task OnRowClickInternal(TableRowClickEventArgs<T> eventArgs)
|
||||||
{
|
{
|
||||||
|
if (eventArgs.Item is null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (MultiSelection)
|
if (MultiSelection)
|
||||||
{
|
{
|
||||||
if (eventArgs.MouseEventArgs.CtrlKey)
|
if (eventArgs.MouseEventArgs.CtrlKey)
|
||||||
@@ -236,7 +240,7 @@ namespace Lantean.QBTMudBlade.Components
|
|||||||
//EqualityComparer<T>.Default.Equals(item, SelectedItem) ||
|
//EqualityComparer<T>.Default.Equals(item, SelectedItem) ||
|
||||||
if (SelectedItems.Contains(item))
|
if (SelectedItems.Contains(item))
|
||||||
{
|
{
|
||||||
style += " background-color: var(--mud-palette-grey-dark); color: var(--mud-palette-grey-light) !important;";
|
style += " background-color: var(--mud-palette-gray-dark); color: var(--mud-palette-gray-light) !important;";
|
||||||
}
|
}
|
||||||
return style;
|
return style;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,8 +17,12 @@ namespace Lantean.QBTMudBlade.Components
|
|||||||
[Parameter]
|
[Parameter]
|
||||||
public bool Disabled { get; set; }
|
public bool Disabled { get; set; }
|
||||||
|
|
||||||
|
[Inject]
|
||||||
|
public ILogger<EnhancedErrorBoundary> Logger { get; set; } = default!;
|
||||||
|
|
||||||
protected override Task OnErrorAsync(Exception exception)
|
protected override Task OnErrorAsync(Exception exception)
|
||||||
{
|
{
|
||||||
|
Logger.LogError(exception, exception.Message);
|
||||||
_exceptions.Add(exception);
|
_exceptions.Add(exception);
|
||||||
|
|
||||||
if (Disabled)
|
if (Disabled)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<MudList Clickable="true">
|
<MudList T="string">
|
||||||
<MudListItem OnClick="ClearErrors">Clear Errors</MudListItem>
|
<MudListItem OnClick="ClearErrors">Clear Errors</MudListItem>
|
||||||
<MudListItem OnClick="ClearErrorsAndResumeAsync">Clear Errors and Resume</MudListItem>
|
<MudListItem OnClick="ClearErrorsAndResumeAsync">Clear Errors and Resume</MudListItem>
|
||||||
<MudDivider />
|
<MudDivider />
|
||||||
|
|||||||
@@ -1,20 +1,20 @@
|
|||||||
<MudToolBar DisableGutters="true" Dense="true">
|
<MudToolBar Gutters="false" Dense="true">
|
||||||
<MudIconButton Icon="@Icons.Material.Filled.DriveFileRenameOutline" OnClick="RenameFile" Title="Rename" />
|
<MudIconButton Icon="@Icons.Material.Filled.DriveFileRenameOutline" OnClick="RenameFile" title="Rename" />
|
||||||
<MudDivider Vertical="true" />
|
<MudDivider Vertical="true" />
|
||||||
<MudIconButton Icon="@Icons.Material.Outlined.ViewColumn" Color="Color.Inherit" OnClick="ColumnOptions" Title="Choose Columns" />
|
<MudIconButton Icon="@Icons.Material.Outlined.ViewColumn" Color="Color.Inherit" OnClick="ColumnOptions" title="Choose Columns" />
|
||||||
<MudDivider Vertical="true" />
|
<MudDivider Vertical="true" />
|
||||||
<MudMenu Icon="@Icons.Material.Outlined.FileDownloadOff" Label="Do Not Download" AnchorOrigin="Origin.BottomLeft" TransformOrigin="Origin.TopLeft" title="Do Not Download">
|
<MudMenu Icon="@Icons.Material.Outlined.FileDownloadOff" Label="Do Not Download" AnchorOrigin="Origin.BottomLeft" TransformOrigin="Origin.TopLeft" title="Do Not Download">
|
||||||
<MudMenuItem OnClick="DoNotDownloadLessThan100PercentAvailability" OnTouch="DoNotDownloadLessThan100PercentAvailability">Less Than 100% Availability</MudMenuItem>
|
<MudMenuItem OnClick="DoNotDownloadLessThan100PercentAvailability">Less Than 100% Availability</MudMenuItem>
|
||||||
<MudMenuItem OnClick="DoNotDownloadLessThan80PercentAvailability" OnTouch="DoNotDownloadLessThan80PercentAvailability">Less than 80% Availability</MudMenuItem>
|
<MudMenuItem OnClick="DoNotDownloadLessThan80PercentAvailability">Less than 80% Availability</MudMenuItem>
|
||||||
<MudMenuItem OnClick="DoNotDownloadCurrentlyFilteredFiles" OnTouch="NormalPriorityCurrentlyFilteredFiles">Currently Filtered Files</MudMenuItem>
|
<MudMenuItem OnClick="DoNotDownloadCurrentlyFilteredFiles">Currently Filtered Files</MudMenuItem>
|
||||||
</MudMenu>
|
</MudMenu>
|
||||||
<MudMenu Icon="@Icons.Material.Outlined.FileDownload" Label="Normal Priority" AnchorOrigin="Origin.BottomLeft" TransformOrigin="Origin.TopLeft" title="Download">
|
<MudMenu Icon="@Icons.Material.Outlined.FileDownload" Label="Normal Priority" AnchorOrigin="Origin.BottomLeft" TransformOrigin="Origin.TopLeft" title="Download">
|
||||||
<MudMenuItem OnClick="NormalPriorityLessThan100PercentAvailability" OnTouch="NormalPriorityLessThan100PercentAvailability">Less Than 100% Availability</MudMenuItem>
|
<MudMenuItem OnClick="NormalPriorityLessThan100PercentAvailability">Less Than 100% Availability</MudMenuItem>
|
||||||
<MudMenuItem OnClick="NormalPriorityLessThan80PercentAvailability" OnTouch="NormalPriorityLessThan80PercentAvailability">Less than 80% Availability</MudMenuItem>
|
<MudMenuItem OnClick="NormalPriorityLessThan80PercentAvailability">Less than 80% Availability</MudMenuItem>
|
||||||
<MudMenuItem OnClick="NormalPriorityCurrentlyFilteredFiles" OnTouch="NormalPriorityCurrentlyFilteredFiles">Currently Filtered Files</MudMenuItem>
|
<MudMenuItem OnClick="NormalPriorityCurrentlyFilteredFiles">Currently Filtered Files</MudMenuItem>
|
||||||
</MudMenu>
|
</MudMenu>
|
||||||
<MudIconButton Icon="@Icons.Material.Outlined.FilterList" OnClick="ShowFilterDialog" Title="Filter" />
|
<MudIconButton Icon="@Icons.Material.Outlined.FilterList" OnClick="ShowFilterDialog" title="Filter" />
|
||||||
<MudIconButton Icon="@Icons.Material.Outlined.FilterListOff" OnClick="RemoveFilter" Title="Remove Filter" />
|
<MudIconButton Icon="@Icons.Material.Outlined.FilterListOff" OnClick="RemoveFilter" title="Remove Filter" />
|
||||||
<MudSpacer />
|
<MudSpacer />
|
||||||
<MudTextField T="string" Value="SearchText" ValueChanged="SearchTextChanged" Immediate="true" DebounceInterval="500" Placeholder="Filter file list" Adornment="Adornment.Start" AdornmentIcon="@Icons.Material.Filled.Search" IconSize="Size.Medium" Class="mt-0"></MudTextField>
|
<MudTextField T="string" Value="SearchText" ValueChanged="SearchTextChanged" Immediate="true" DebounceInterval="500" Placeholder="Filter file list" Adornment="Adornment.Start" AdornmentIcon="@Icons.Material.Filled.Search" IconSize="Size.Medium" Class="mt-0"></MudTextField>
|
||||||
</MudToolBar>
|
</MudToolBar>
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ namespace Lantean.QBTMudBlade.Components
|
|||||||
var result = await DialogService.ShowAsync<FilterOptionsDialog<ContentItem>>("Filters", parameters, DialogHelper.FormDialogOptions);
|
var result = await DialogService.ShowAsync<FilterOptionsDialog<ContentItem>>("Filters", parameters, DialogHelper.FormDialogOptions);
|
||||||
|
|
||||||
var dialogResult = await result.Result;
|
var dialogResult = await result.Result;
|
||||||
if (dialogResult.Canceled)
|
if (dialogResult is null || dialogResult.Canceled || dialogResult.Data is null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<MudMenu Icon="@Icons.Material.Filled.MoreVert" Color="Color.Inherit" Dense="true" AnchorOrigin="Origin.BottomLeft" TransformOrigin="Origin.TopLeft">
|
<MudMenu Icon="@Icons.Material.Filled.MoreVert" Color="Color.Inherit" Dense="true" AnchorOrigin="Origin.BottomRight" TransformOrigin="Origin.TopLeft">
|
||||||
<MudMenuItem Icon="@Icons.Material.Filled.PieChart" Href="/statistics">Statistics</MudMenuItem>
|
<MudMenuItem Icon="@Icons.Material.Filled.PieChart" Href="/statistics">Statistics</MudMenuItem>
|
||||||
<MudMenuItem Icon="@Icons.Material.Filled.Search" Href="/search">Search</MudMenuItem>
|
<MudMenuItem Icon="@Icons.Material.Filled.Search" Href="/search">Search</MudMenuItem>
|
||||||
<MudMenuItem Icon="@Icons.Material.Filled.RssFeed" Href="/rss">RSS</MudMenuItem>
|
<MudMenuItem Icon="@Icons.Material.Filled.RssFeed" Href="/rss">RSS</MudMenuItem>
|
||||||
@@ -6,8 +6,8 @@
|
|||||||
<MudMenuItem Icon="@Icons.Material.Filled.DisabledByDefault" Href="/blocks">Blocked IPs</MudMenuItem>
|
<MudMenuItem Icon="@Icons.Material.Filled.DisabledByDefault" Href="/blocks">Blocked IPs</MudMenuItem>
|
||||||
<MudDivider />
|
<MudDivider />
|
||||||
<MudMenuItem Icon="@Icons.Material.Filled.Settings" Href="/settings">Settings</MudMenuItem>
|
<MudMenuItem Icon="@Icons.Material.Filled.Settings" Href="/settings">Settings</MudMenuItem>
|
||||||
<MudMenuItem Icon="@Icons.Material.Filled.Undo" OnClick="ResetWebUI" OnTouch="ResetWebUI">Reset Web UI</MudMenuItem>
|
<MudMenuItem Icon="@Icons.Material.Filled.Undo" OnClick="ResetWebUI">Reset Web UI</MudMenuItem>
|
||||||
<MudDivider />
|
<MudDivider />
|
||||||
<MudMenuItem Icon="@Icons.Material.Filled.Logout" OnClick="Logout" OnTouch="Logout">Logout</MudMenuItem>
|
<MudMenuItem Icon="@Icons.Material.Filled.Logout" OnClick="Logout">Logout</MudMenuItem>
|
||||||
<MudMenuItem Icon="@Icons.Material.Filled.ExitToApp" OnClick="Exit" OnTouch="Exit">Exit qBittorrent</MudMenuItem>
|
<MudMenuItem Icon="@Icons.Material.Filled.ExitToApp" OnClick="Exit">Exit qBittorrent</MudMenuItem>
|
||||||
</MudMenu>
|
</MudMenu>
|
||||||
@@ -289,7 +289,7 @@
|
|||||||
</MudItem>
|
</MudItem>
|
||||||
<MudItem xs="12">
|
<MudItem xs="12">
|
||||||
<MudText>Supported parameters (case sensitive):</MudText>
|
<MudText>Supported parameters (case sensitive):</MudText>
|
||||||
<MudList>
|
<MudList T="string" ReadOnly="true">
|
||||||
<MudListItem>%N: Torrent name</MudListItem>
|
<MudListItem>%N: Torrent name</MudListItem>
|
||||||
<MudListItem>%L: Category</MudListItem>
|
<MudListItem>%L: Category</MudListItem>
|
||||||
<MudListItem>%G: Tags (separated by comma)</MudListItem>
|
<MudListItem>%G: Tags (separated by comma)</MudListItem>
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ namespace Lantean.QBTMudBlade.Components
|
|||||||
[Parameter]
|
[Parameter]
|
||||||
public bool Active { get; set; }
|
public bool Active { get; set; }
|
||||||
|
|
||||||
[CascadingParameter]
|
[CascadingParameter(Name = "RefreshInterval")]
|
||||||
public int RefreshInterval { get; set; }
|
public int RefreshInterval { get; set; }
|
||||||
|
|
||||||
[CascadingParameter]
|
[CascadingParameter]
|
||||||
|
|||||||
@@ -51,9 +51,9 @@ namespace Lantean.QBTMudBlade.Components
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
downloadingColor = Theme.Palette.Success.ToString(MudBlazor.Utilities.MudColorOutputFormats.RGBA);
|
downloadingColor = Theme.PaletteLight.Success.ToString(MudBlazor.Utilities.MudColorOutputFormats.RGBA);
|
||||||
haveColor = Theme.Palette.Info.ToString(MudBlazor.Utilities.MudColorOutputFormats.RGBA);
|
haveColor = Theme.PaletteLight.Info.ToString(MudBlazor.Utilities.MudColorOutputFormats.RGBA);
|
||||||
borderColor = Theme.Palette.Black.ToString(MudBlazor.Utilities.MudColorOutputFormats.RGBA);
|
borderColor = Theme.PaletteLight.Black.ToString(MudBlazor.Utilities.MudColorOutputFormats.RGBA);
|
||||||
}
|
}
|
||||||
await JSRuntime.RenderPiecesBar("progress", Hash, Pieces.Select(s => (int)s).ToArray(), downloadingColor, haveColor, borderColor);
|
await JSRuntime.RenderPiecesBar("progress", Hash, Pieces.Select(s => (int)s).ToArray(), downloadingColor, haveColor, borderColor);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
@if (RenderType == RenderType.Toolbar)
|
@if (RenderType == RenderType.Toolbar)
|
||||||
{
|
{
|
||||||
<MudToolBar Dense="true" DisableGutters="true" WrapContent="true">
|
<MudToolBar Dense="true" Gutters="false" WrapContent="true">
|
||||||
@ToolbarContent
|
@ToolbarContent
|
||||||
</MudToolBar>
|
</MudToolBar>
|
||||||
}
|
}
|
||||||
@@ -10,7 +10,7 @@ else if (RenderType == RenderType.ToolbarContents)
|
|||||||
}
|
}
|
||||||
else if (RenderType == RenderType.MixedToolbar)
|
else if (RenderType == RenderType.MixedToolbar)
|
||||||
{
|
{
|
||||||
<MudToolBar Dense="true" DisableGutters="true" WrapContent="true">
|
<MudToolBar Dense="true" Gutters="false" WrapContent="true">
|
||||||
@MixedToolbarContent
|
@MixedToolbarContent
|
||||||
</MudToolBar>
|
</MudToolBar>
|
||||||
}
|
}
|
||||||
@@ -27,7 +27,7 @@ else if (RenderType == RenderType.InitialIconsOnly)
|
|||||||
<MudDivider Vertical="true" />
|
<MudDivider Vertical="true" />
|
||||||
}
|
}
|
||||||
|
|
||||||
<MudIconButton Title="@action.Text" Icon="@action.Icon" Color="action.Color" OnClick="action.Callback" Disabled="Disabled" />
|
<MudIconButton title="@action.Text" Icon="@action.Icon" Color="action.Color" OnClick="action.Callback" Disabled="Disabled" />
|
||||||
}
|
}
|
||||||
|
|
||||||
@Menu(Actions.Skip(5))
|
@Menu(Actions.Skip(5))
|
||||||
@@ -37,7 +37,7 @@ else if (RenderType == RenderType.Children)
|
|||||||
var parent = Actions.FirstOrDefault(a => a.Text == ParentAction?.Text);
|
var parent = Actions.FirstOrDefault(a => a.Text == ParentAction?.Text);
|
||||||
if (parent is not null)
|
if (parent is not null)
|
||||||
{
|
{
|
||||||
<MudList Clickable="true">
|
<MudList T="string">
|
||||||
@foreach (var action in parent.Children)
|
@foreach (var action in parent.Children)
|
||||||
{
|
{
|
||||||
@if (action.SeparatorBefore)
|
@if (action.SeparatorBefore)
|
||||||
@@ -77,7 +77,7 @@ else
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<MudIconButton Title="@action.Text" Icon="@action.Icon" Color="action.Color" OnClick="action.Callback" Disabled="Disabled" />
|
<MudIconButton title="@action.Text" Icon="@action.Icon" Color="action.Color" OnClick="action.Callback" Disabled="Disabled" />
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -115,7 +115,7 @@ else
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<MudIconButton Title="@action.Text" Icon="@action.Icon" Color="action.Color" OnClick="action.Callback" Disabled="Disabled" />
|
<MudIconButton title="@action.Text" Icon="@action.Icon" Color="action.Color" OnClick="action.Callback" Disabled="Disabled" />
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -141,7 +141,7 @@ else
|
|||||||
<MudDivider />
|
<MudDivider />
|
||||||
}
|
}
|
||||||
|
|
||||||
<MudMenuItem Icon="@action.Icon" IconColor="action.Color" OnClick="action.Callback" OnTouch="action.Callback" Disabled="Disabled">@action.Text</MudMenuItem>
|
<MudMenuItem Icon="@action.Icon" IconColor="action.Color" OnClick="action.Callback" Disabled="Disabled">@action.Text</MudMenuItem>
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -149,7 +149,7 @@ else
|
|||||||
{
|
{
|
||||||
return __builder =>
|
return __builder =>
|
||||||
{
|
{
|
||||||
<MudMenu Dense="true" AnchorOrigin="Origin.BottomLeft" TransformOrigin="Origin.TopLeft" Label="Actions" EndIcon="@Icons.Material.Filled.ArrowDropDown" @ref="ActionsMenu" Disabled="@(!Hashes.Any())">
|
<MudMenu Dense="true" AnchorOrigin="Origin.BottomLeft" TransformOrigin="Origin.TopLeft" Label="Actions" EndIcon="@Icons.Material.Filled.ArrowDropDown" @ref="ActionsMenu" Disabled="@(!Hashes.Any())" ActivationEvent="MouseEvent.LeftClick">
|
||||||
@foreach (var action in actions)
|
@foreach (var action in actions)
|
||||||
{
|
{
|
||||||
@if (action.SeparatorBefore)
|
@if (action.SeparatorBefore)
|
||||||
@@ -159,14 +159,14 @@ else
|
|||||||
|
|
||||||
if (!action.Children.Any())
|
if (!action.Children.Any())
|
||||||
{
|
{
|
||||||
<MudMenuItem Icon="@action.Icon" IconColor="action.Color" OnClick="action.Callback" OnTouch="action.Callback" Disabled="Disabled">
|
<MudMenuItem Icon="@action.Icon" IconColor="action.Color" OnClick="action.Callback" Disabled="Disabled">
|
||||||
@action.Text
|
@action.Text
|
||||||
</MudMenuItem>
|
</MudMenuItem>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<MudMenuItem Icon="@action.Icon" IconColor="action.Color" OnTouch="@(t => SubMenuTouch(action))" OnClick="@(t => SubMenuTouch(action))">
|
<MudMenuItem Icon="@action.Icon" IconColor="action.Color" OnClick="@(t => SubMenuTouch(action))">
|
||||||
<MudMenu Dense="true" AnchorOrigin="Origin.TopRight" TransformOrigin="Origin.TopLeft" ActivationEvent="MouseEvent.MouseOver" Icon="@Icons.Material.Filled.ArrowDropDown" DisableElevation="true" DisableRipple="true" Class="sub-menu">
|
<MudMenu Dense="true" AnchorOrigin="Origin.TopRight" TransformOrigin="Origin.TopLeft" ActivationEvent="MouseEvent.MouseOver" Icon="@Icons.Material.Filled.ArrowDropDown" Ripple="false" Class="sub-menu">
|
||||||
<ActivatorContent>
|
<ActivatorContent>
|
||||||
@action.Text
|
@action.Text
|
||||||
</ActivatorContent>
|
</ActivatorContent>
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ namespace Lantean.QBTMudBlade.Components
|
|||||||
{
|
{
|
||||||
new TorrentAction("start", "Start", Icons.Material.Filled.PlayArrow, Color.Success, CreateCallback(Resume)),
|
new TorrentAction("start", "Start", Icons.Material.Filled.PlayArrow, Color.Success, CreateCallback(Resume)),
|
||||||
new TorrentAction("pause", "Pause", Icons.Material.Filled.Pause, Color.Warning, CreateCallback(Pause)),
|
new TorrentAction("pause", "Pause", Icons.Material.Filled.Pause, Color.Warning, CreateCallback(Pause)),
|
||||||
new TorrentAction("forceStart", "Force start", Icons.Material.Filled.Pause, Color.Warning, CreateCallback(ForceStart)),
|
new TorrentAction("forceStart", "Force start", Icons.Material.Filled.Forward, Color.Warning, CreateCallback(ForceStart)),
|
||||||
new TorrentAction("delete", "Remove", Icons.Material.Filled.Delete, Color.Error, CreateCallback(Remove), separatorBefore: true),
|
new TorrentAction("delete", "Remove", Icons.Material.Filled.Delete, Color.Error, CreateCallback(Remove), separatorBefore: true),
|
||||||
new TorrentAction("setLocation", "Set location", Icons.Material.Filled.MyLocation, Color.Info, CreateCallback(SetLocation), separatorBefore: true),
|
new TorrentAction("setLocation", "Set location", Icons.Material.Filled.MyLocation, Color.Info, CreateCallback(SetLocation), separatorBefore: true),
|
||||||
new TorrentAction("rename", "Rename", Icons.Material.Filled.DriveFileRenameOutline, Color.Info, CreateCallback(Rename)),
|
new TorrentAction("rename", "Rename", Icons.Material.Filled.DriveFileRenameOutline, Color.Info, CreateCallback(Rename)),
|
||||||
@@ -248,7 +248,10 @@ namespace Lantean.QBTMudBlade.Components
|
|||||||
protected async Task Copy(Func<Torrent, object?> selector)
|
protected async Task Copy(Func<Torrent, object?> selector)
|
||||||
{
|
{
|
||||||
await Copy(string.Join(Environment.NewLine, GetTorrents().Select(selector)));
|
await Copy(string.Join(Environment.NewLine, GetTorrents().Select(selector)));
|
||||||
ActionsMenu?.CloseMenu();
|
if (ActionsMenu is not null)
|
||||||
|
{
|
||||||
|
await ActionsMenu.CloseMenuAsync();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async Task Export()
|
protected async Task Export()
|
||||||
@@ -487,7 +490,6 @@ namespace Lantean.QBTMudBlade.Components
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
||||||
if (actionState.Show is null || actionState.Show.Value)
|
if (actionState.Show is null || actionState.Show.Value)
|
||||||
{
|
{
|
||||||
var act = action with { };
|
var act = action with { };
|
||||||
@@ -499,6 +501,8 @@ namespace Lantean.QBTMudBlade.Components
|
|||||||
{
|
{
|
||||||
act.IsChecked = actionState.IsChecked.Value;
|
act.IsChecked = actionState.IsChecked.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
yield return act;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
<MudToolBar Dense="true" DisableGutters="true" WrapContent="true">
|
<MudToolBar Dense="true" Gutters="false" WrapContent="true">
|
||||||
@{
|
@{
|
||||||
var (icon, color) = DisplayHelpers.GetStateIcon(Torrent.State);
|
var (icon, color) = DisplayHelpers.GetStateIcon(Torrent.State);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ namespace Lantean.QBTMudBlade.Components
|
|||||||
[Parameter]
|
[Parameter]
|
||||||
public bool Active { get; set; }
|
public bool Active { get; set; }
|
||||||
|
|
||||||
[CascadingParameter]
|
[CascadingParameter(Name = "RefreshInterval")]
|
||||||
public int RefreshInterval { get; set; }
|
public int RefreshInterval { get; set; }
|
||||||
|
|
||||||
[Inject]
|
[Inject]
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ namespace Lantean.QBTMudBlade.Components
|
|||||||
[Parameter, EditorRequired]
|
[Parameter, EditorRequired]
|
||||||
public string? Hash { get; set; }
|
public string? Hash { get; set; }
|
||||||
|
|
||||||
[CascadingParameter]
|
[CascadingParameter(Name = "RefreshInterval")]
|
||||||
public int RefreshInterval { get; set; }
|
public int RefreshInterval { get; set; }
|
||||||
|
|
||||||
[Inject]
|
[Inject]
|
||||||
|
|||||||
@@ -9,11 +9,11 @@ namespace Lantean.QBTMudBlade
|
|||||||
{
|
{
|
||||||
public static class DialogHelper
|
public static class DialogHelper
|
||||||
{
|
{
|
||||||
public static readonly DialogOptions FormDialogOptions = new() { CloseButton = true, MaxWidth = MaxWidth.Medium, ClassBackground = "background-blur", FullWidth = true };
|
public static readonly DialogOptions FormDialogOptions = new() { CloseButton = true, MaxWidth = MaxWidth.Medium, BackgroundClass = "background-blur", FullWidth = true };
|
||||||
|
|
||||||
public static readonly DialogOptions NonBlurFormDialogOptions = new() { CloseButton = true, MaxWidth = MaxWidth.Medium, FullWidth = true };
|
public static readonly DialogOptions NonBlurFormDialogOptions = new() { CloseButton = true, MaxWidth = MaxWidth.Medium, FullWidth = true };
|
||||||
|
|
||||||
public static readonly DialogOptions ConfirmDialogOptions = new() { ClassBackground = "background-blur", MaxWidth = MaxWidth.Small, FullWidth = true };
|
public static readonly DialogOptions ConfirmDialogOptions = new() { BackgroundClass = "background-blur", MaxWidth = MaxWidth.Small, FullWidth = true };
|
||||||
|
|
||||||
public static readonly DialogOptions NonBlurConfirmDialogOptions = new() { MaxWidth = MaxWidth.Small, FullWidth = true };
|
public static readonly DialogOptions NonBlurConfirmDialogOptions = new() { MaxWidth = MaxWidth.Small, FullWidth = true };
|
||||||
|
|
||||||
@@ -23,7 +23,7 @@ namespace Lantean.QBTMudBlade
|
|||||||
{
|
{
|
||||||
var result = await dialogService.ShowAsync<AddTorrentFileDialog>("Upload local torrent", FormDialogOptions);
|
var result = await dialogService.ShowAsync<AddTorrentFileDialog>("Upload local torrent", FormDialogOptions);
|
||||||
var dialogResult = await result.Result;
|
var dialogResult = await result.Result;
|
||||||
if (dialogResult.Canceled)
|
if (dialogResult is null || dialogResult.Canceled || dialogResult.Data is null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -69,7 +69,7 @@ namespace Lantean.QBTMudBlade
|
|||||||
{
|
{
|
||||||
var result = await dialogService.ShowAsync<AddTorrentLinkDialog>("Download from URLs", FormDialogOptions);
|
var result = await dialogService.ShowAsync<AddTorrentLinkDialog>("Download from URLs", FormDialogOptions);
|
||||||
var dialogResult = await result.Result;
|
var dialogResult = await result.Result;
|
||||||
if (dialogResult.Canceled)
|
if (dialogResult is null || dialogResult.Canceled || dialogResult.Data is null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -104,13 +104,13 @@ namespace Lantean.QBTMudBlade
|
|||||||
};
|
};
|
||||||
|
|
||||||
var reference = await dialogService.ShowAsync<DeleteDialog>($"Remove torrent{(hashes.Length == 1 ? "" : "s")}?", parameters, ConfirmDialogOptions);
|
var reference = await dialogService.ShowAsync<DeleteDialog>($"Remove torrent{(hashes.Length == 1 ? "" : "s")}?", parameters, ConfirmDialogOptions);
|
||||||
var result = await reference.Result;
|
var dialogResult = await reference.Result;
|
||||||
if (result.Canceled)
|
if (dialogResult is null || dialogResult.Canceled || dialogResult.Data is null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await apiClient.DeleteTorrents(hashes, (bool)result.Data);
|
await apiClient.DeleteTorrents(hashes, (bool)dialogResult.Data);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task InvokeRenameFilesDialog(this IDialogService dialogService, IApiClient apiClient, string hash)
|
public static async Task InvokeRenameFilesDialog(this IDialogService dialogService, IApiClient apiClient, string hash)
|
||||||
@@ -121,13 +121,13 @@ namespace Lantean.QBTMudBlade
|
|||||||
public static async Task<string?> ShowAddCategoryDialog(this IDialogService dialogService, IApiClient apiClient)
|
public static async Task<string?> ShowAddCategoryDialog(this IDialogService dialogService, IApiClient apiClient)
|
||||||
{
|
{
|
||||||
var reference = await dialogService.ShowAsync<AddCategoryDialog>("New Category", NonBlurFormDialogOptions);
|
var reference = await dialogService.ShowAsync<AddCategoryDialog>("New Category", NonBlurFormDialogOptions);
|
||||||
var result = await reference.Result;
|
var dialogResult = await reference.Result;
|
||||||
if (result.Canceled)
|
if (dialogResult is null || dialogResult.Canceled || dialogResult.Data is null)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
var category = (Category)result.Data;
|
var category = (Category)dialogResult.Data;
|
||||||
|
|
||||||
await apiClient.AddCategory(category.Name, category.SavePath);
|
await apiClient.AddCategory(category.Name, category.SavePath);
|
||||||
|
|
||||||
@@ -136,15 +136,15 @@ namespace Lantean.QBTMudBlade
|
|||||||
|
|
||||||
public static async Task<HashSet<string>?> ShowAddTagsDialog(this IDialogService dialogService, IApiClient apiClient)
|
public static async Task<HashSet<string>?> ShowAddTagsDialog(this IDialogService dialogService, IApiClient apiClient)
|
||||||
{
|
{
|
||||||
var dialogReference = await dialogService.ShowAsync<AddTagDialog>("Add Tags", NonBlurFormDialogOptions);
|
var reference = await dialogService.ShowAsync<AddTagDialog>("Add Tags", NonBlurFormDialogOptions);
|
||||||
var result = await dialogReference.Result;
|
var dialogResult = await reference.Result;
|
||||||
|
|
||||||
if (result.Canceled)
|
if (dialogResult is null || dialogResult.Canceled || dialogResult.Data is null)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
var tags = (HashSet<string>)result.Data;
|
var tags = (HashSet<string>)dialogResult.Data;
|
||||||
|
|
||||||
return tags;
|
return tags;
|
||||||
}
|
}
|
||||||
@@ -158,7 +158,7 @@ namespace Lantean.QBTMudBlade
|
|||||||
var result = await dialogService.ShowAsync<ConfirmDialog>(title, parameters, ConfirmDialogOptions);
|
var result = await dialogService.ShowAsync<ConfirmDialog>(title, parameters, ConfirmDialogOptions);
|
||||||
|
|
||||||
var dialogResult = await result.Result;
|
var dialogResult = await result.Result;
|
||||||
return !dialogResult.Canceled;
|
return dialogResult is not null && !dialogResult.Canceled;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task ShowConfirmDialog(this IDialogService dialogService, string title, string content, Func<Task> onSuccess)
|
public static async Task ShowConfirmDialog(this IDialogService dialogService, string title, string content, Func<Task> onSuccess)
|
||||||
@@ -170,7 +170,7 @@ namespace Lantean.QBTMudBlade
|
|||||||
var result = await dialogService.ShowAsync<ConfirmDialog>(title, parameters, ConfirmDialogOptions);
|
var result = await dialogService.ShowAsync<ConfirmDialog>(title, parameters, ConfirmDialogOptions);
|
||||||
|
|
||||||
var dialogResult = await result.Result;
|
var dialogResult = await result.Result;
|
||||||
if (dialogResult.Canceled)
|
if (dialogResult is null || dialogResult.Canceled || dialogResult.Data is null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -198,7 +198,7 @@ namespace Lantean.QBTMudBlade
|
|||||||
var result = await dialogService.ShowAsync<SingleFieldDialog<T>>(title, parameters, FormDialogOptions);
|
var result = await dialogService.ShowAsync<SingleFieldDialog<T>>(title, parameters, FormDialogOptions);
|
||||||
|
|
||||||
var dialogResult = await result.Result;
|
var dialogResult = await result.Result;
|
||||||
if (dialogResult.Canceled)
|
if (dialogResult is null || dialogResult.Canceled || dialogResult.Data is null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -217,7 +217,7 @@ namespace Lantean.QBTMudBlade
|
|||||||
var result = await dialogService.ShowAsync<SliderFieldDialog<long>>("Download Rate", parameters, FormDialogOptions);
|
var result = await dialogService.ShowAsync<SliderFieldDialog<long>>("Download Rate", parameters, FormDialogOptions);
|
||||||
|
|
||||||
var dialogResult = await result.Result;
|
var dialogResult = await result.Result;
|
||||||
if (dialogResult.Canceled)
|
if (dialogResult is null || dialogResult.Canceled || dialogResult.Data is null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -236,7 +236,7 @@ namespace Lantean.QBTMudBlade
|
|||||||
var result = await dialogService.ShowAsync<SliderFieldDialog<long>>("Upload Rate", parameters, FormDialogOptions);
|
var result = await dialogService.ShowAsync<SliderFieldDialog<long>>("Upload Rate", parameters, FormDialogOptions);
|
||||||
|
|
||||||
var dialogResult = await result.Result;
|
var dialogResult = await result.Result;
|
||||||
if (dialogResult.Canceled)
|
if (dialogResult is null || dialogResult.Canceled || dialogResult.Data is null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -255,7 +255,7 @@ namespace Lantean.QBTMudBlade
|
|||||||
var result = await dialogService.ShowAsync<SliderFieldDialog<float>>("Upload Rate", parameters, FormDialogOptions);
|
var result = await dialogService.ShowAsync<SliderFieldDialog<float>>("Upload Rate", parameters, FormDialogOptions);
|
||||||
|
|
||||||
var dialogResult = await result.Result;
|
var dialogResult = await result.Result;
|
||||||
if (dialogResult.Canceled)
|
if (dialogResult is null || dialogResult.Canceled || dialogResult.Data is null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -273,7 +273,7 @@ namespace Lantean.QBTMudBlade
|
|||||||
var result = await dialogService.ShowAsync<FilterOptionsDialog<T>>("Filters", parameters, FormDialogOptions);
|
var result = await dialogService.ShowAsync<FilterOptionsDialog<T>>("Filters", parameters, FormDialogOptions);
|
||||||
|
|
||||||
var dialogResult = await result.Result;
|
var dialogResult = await result.Result;
|
||||||
if (dialogResult.Canceled)
|
if (dialogResult is null || dialogResult.Canceled || dialogResult.Data is null)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -291,13 +291,13 @@ namespace Lantean.QBTMudBlade
|
|||||||
};
|
};
|
||||||
|
|
||||||
var reference = await dialogService.ShowAsync<ColumnOptionsDialog<T>>("Column Options", parameters, FormDialogOptions);
|
var reference = await dialogService.ShowAsync<ColumnOptionsDialog<T>>("Column Options", parameters, FormDialogOptions);
|
||||||
var result = await reference.Result;
|
var dialogResult = await reference.Result;
|
||||||
if (result.Canceled)
|
if (dialogResult is null || dialogResult.Canceled || dialogResult.Data is null)
|
||||||
{
|
{
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ((HashSet<string>, Dictionary<string, int?>))result.Data;
|
return ((HashSet<string>, Dictionary<string, int?>))dialogResult.Data;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task InvokeRssRulesDialog(this IDialogService dialogService)
|
public static async Task InvokeRssRulesDialog(this IDialogService dialogService)
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="8.0.6" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="8.0.6" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="8.0.6" PrivateAssets="all" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="8.0.6" PrivateAssets="all" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.0" />
|
||||||
<PackageReference Include="MudBlazor" Version="6.20.0" />
|
<PackageReference Include="MudBlazor" Version="7.0.0-rc.2" />
|
||||||
<PackageReference Include="MudBlazor.ThemeManager" Version="1.1.0" />
|
<PackageReference Include="MudBlazor.ThemeManager" Version="1.1.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
@inherits LayoutComponentBase
|
@inherits LayoutComponentBase
|
||||||
@layout LoggedInLayout
|
@layout LoggedInLayout
|
||||||
|
|
||||||
<MudDrawer Open="DrawerOpen" ClipMode="DrawerClipMode.Always" Elevation="2" DisableOverlay="true">
|
<MudDrawer Open="DrawerOpen" ClipMode="DrawerClipMode.Always" Elevation="2" Overlay="false">
|
||||||
<TorrentsListNav Torrents="Torrents" SelectedTorrent="@SelectedTorrent" SortDirection="SortDirection" SortColumn="@SortColumn" />
|
<TorrentsListNav Torrents="Torrents" SelectedTorrent="@SelectedTorrent" SortDirection="SortDirection" SortColumn="@SortColumn" />
|
||||||
</MudDrawer>
|
</MudDrawer>
|
||||||
<MudMainContent>
|
<MudMainContent>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
@inherits LayoutComponentBase
|
@inherits LayoutComponentBase
|
||||||
@layout LoggedInLayout
|
@layout LoggedInLayout
|
||||||
|
|
||||||
<MudDrawer Open="DrawerOpen" ClipMode="DrawerClipMode.Always" Elevation="2" DisableOverlay="true">
|
<MudDrawer Open="DrawerOpen" ClipMode="DrawerClipMode.Always" Elevation="2" Overlay="false">
|
||||||
<FiltersNav CategoryChanged="CategoryChanged" StatusChanged="StatusChanged" TagChanged="TagChanged" TrackerChanged="TrackerChanged" />
|
<FiltersNav CategoryChanged="CategoryChanged" StatusChanged="StatusChanged" TagChanged="TagChanged" TrackerChanged="TrackerChanged" />
|
||||||
</MudDrawer>
|
</MudDrawer>
|
||||||
<MudMainContent>
|
<MudMainContent>
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
<MudThemeProvider @ref="MudThemeProvider" @bind-IsDarkMode="IsDarkMode" Theme="Theme" />
|
<MudThemeProvider @ref="MudThemeProvider" @bind-IsDarkMode="IsDarkMode" Theme="Theme" />
|
||||||
<MudDialogProvider />
|
<MudDialogProvider />
|
||||||
<MudSnackbarProvider />
|
<MudSnackbarProvider />
|
||||||
|
<MudPopoverProvider />
|
||||||
|
|
||||||
<PageTitle>qBittorrent Web UI</PageTitle>
|
<PageTitle>qBittorrent Web UI</PageTitle>
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
@inherits LayoutComponentBase
|
@inherits LayoutComponentBase
|
||||||
@layout LoggedInLayout
|
@layout LoggedInLayout
|
||||||
|
|
||||||
<MudDrawer Open="DrawerOpen" ClipMode="DrawerClipMode.Always" Elevation="2" DisableOverlay="true">
|
<MudDrawer Open="DrawerOpen" ClipMode="DrawerClipMode.Always" Elevation="2" Overlay="false">
|
||||||
<MudNavMenu>
|
<MudNavMenu>
|
||||||
<MudNavLink Icon="@(Icons.Material.Outlined.NavigateBefore)" OnClick="NavigateBack">Back</MudNavLink>
|
<MudNavLink Icon="@(Icons.Material.Outlined.NavigateBefore)" OnClick="NavigateBack">Back</MudNavLink>
|
||||||
<MudDivider />
|
<MudDivider />
|
||||||
|
|||||||
16
Lantean.QBTMudBlade/Models/LogForm.cs
Normal file
16
Lantean.QBTMudBlade/Models/LogForm.cs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
namespace Lantean.QBTMudBlade.Models
|
||||||
|
{
|
||||||
|
public class LogForm
|
||||||
|
{
|
||||||
|
public bool Normal => SelectedTypes.Contains("Normal");
|
||||||
|
public bool Info => SelectedTypes.Contains("Info");
|
||||||
|
public bool Warning => SelectedTypes.Contains("Warning");
|
||||||
|
public bool Critical => SelectedTypes.Contains("Critical");
|
||||||
|
|
||||||
|
public int? LastKnownId { get; set; }
|
||||||
|
|
||||||
|
public IEnumerable<string> SelectedTypes { get; set; } = new HashSet<string>();
|
||||||
|
|
||||||
|
public string? Criteria { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
16
Lantean.QBTMudBlade/Models/LoginForm.cs
Normal file
16
Lantean.QBTMudBlade/Models/LoginForm.cs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
|
||||||
|
namespace Lantean.QBTMudBlade.Models
|
||||||
|
{
|
||||||
|
public class LoginForm
|
||||||
|
{
|
||||||
|
[Required]
|
||||||
|
[NotNull]
|
||||||
|
public string? Username { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
[NotNull]
|
||||||
|
public string? Password { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Lantean.QBTMudBlade/Models/SearchForm.cs
Normal file
11
Lantean.QBTMudBlade/Models/SearchForm.cs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
namespace Lantean.QBTMudBlade.Models
|
||||||
|
{
|
||||||
|
public class SearchForm
|
||||||
|
{
|
||||||
|
public string? SearchText { get; set; }
|
||||||
|
|
||||||
|
public string SelectedPlugin { get; set; } = "all";
|
||||||
|
|
||||||
|
public string SelectedCategory { get; set; } = "all";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,16 +1,59 @@
|
|||||||
@page "/blocks"
|
@page "/blocks"
|
||||||
@layout OtherLayout
|
@layout OtherLayout
|
||||||
|
|
||||||
<MudToolBar DisableGutters="true" Dense="true">
|
<MudToolBar Gutters="false" Dense="true">
|
||||||
@if (!DrawerOpen)
|
@if (!DrawerOpen)
|
||||||
{
|
{
|
||||||
<MudIconButton Icon="@Icons.Material.Outlined.NavigateBefore" OnClick="NavigateBack" Title="Back to torrent list" />
|
<MudIconButton Icon="@Icons.Material.Outlined.NavigateBefore" OnClick="NavigateBack" title="Back to torrent list" />
|
||||||
<MudDivider Vertical="true" />
|
<MudDivider Vertical="true" />
|
||||||
}
|
}
|
||||||
<MudDivider Vertical="true" />
|
<MudDivider Vertical="true" />
|
||||||
<MudText Class="pl-5 no-wrap">Blocked IPs</MudText>
|
<MudText Class="pl-5 no-wrap">Blocked IPs</MudText>
|
||||||
</MudToolBar>
|
</MudToolBar>
|
||||||
|
|
||||||
<MudContainer MaxWidth="MaxWidth.ExtraExtraLarge" Class="details-tab-contents">
|
<MudCard Elevation="1" Class="ml-4 mr-4 mb-4">
|
||||||
<p>Coming soon.</p>
|
<MudCardContent>
|
||||||
</MudContainer>
|
<EditForm Model="Model" OnSubmit="Submit">
|
||||||
|
<MudGrid>
|
||||||
|
<MudItem md="10">
|
||||||
|
<MudTextField T="string" Label="Criteria" @bind-Value="Model.Criteria" ShrinkLabel Variant="Variant.Outlined" />
|
||||||
|
</MudItem>
|
||||||
|
<MudItem md="2">
|
||||||
|
<MudButton ButtonType="ButtonType.Submit" FullWidth="true" Color="Color.Primary" EndIcon="@Icons.Material.Filled.Search" Variant="Variant.Filled" Class="mt-6">Filter</MudButton>
|
||||||
|
</MudItem>
|
||||||
|
</MudGrid>
|
||||||
|
</EditForm>
|
||||||
|
</MudCardContent>
|
||||||
|
</MudCard>
|
||||||
|
|
||||||
|
<MudTable Items="Results"
|
||||||
|
T="Lantean.QBitTorrentClient.Models.PeerLog"
|
||||||
|
Hover="true"
|
||||||
|
FixedHeader="true"
|
||||||
|
HeaderClass="table-head-bordered"
|
||||||
|
Dense="true"
|
||||||
|
Breakpoint="Breakpoint.None"
|
||||||
|
Bordered="true"
|
||||||
|
Square="true"
|
||||||
|
LoadingProgressColor="Color.Info"
|
||||||
|
HorizontalScrollbar="true"
|
||||||
|
Virtualize="true"
|
||||||
|
AllowUnsorted="false"
|
||||||
|
SelectOnRowClick="false"
|
||||||
|
Class="search-list"
|
||||||
|
RowClassFunc="RowClass">
|
||||||
|
<HeaderContent>
|
||||||
|
<MudTh>Id</MudTh>
|
||||||
|
<MudTh>Message</MudTh>
|
||||||
|
<MudTh>Timestamp</MudTh>
|
||||||
|
<MudTh>Status</MudTh>
|
||||||
|
<MudTh>Reason</MudTh>
|
||||||
|
</HeaderContent>
|
||||||
|
<RowTemplate>
|
||||||
|
<MudTd DataLabel="Id">@context.Id</MudTd>
|
||||||
|
<MudTd DataLabel="IP">@context.IPAddress</MudTd>
|
||||||
|
<MudTd DataLabel="Timestamp">@DisplayHelpers.DateTime(context.Timestamp)</MudTd>
|
||||||
|
<MudTd DataLabel="Status">@(context.Blocked ? "Blocked" : "Banned")</MudTd>
|
||||||
|
<MudTd DataLabel="Reason">@context.Reason</MudTd>
|
||||||
|
</RowTemplate>
|
||||||
|
</MudTable>
|
||||||
|
|||||||
@@ -1,12 +1,21 @@
|
|||||||
using Lantean.QBitTorrentClient;
|
using Blazored.LocalStorage;
|
||||||
|
using Lantean.QBitTorrentClient;
|
||||||
using Lantean.QBTMudBlade.Models;
|
using Lantean.QBTMudBlade.Models;
|
||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
|
using Microsoft.AspNetCore.Components.Forms;
|
||||||
using MudBlazor;
|
using MudBlazor;
|
||||||
|
using System.Net;
|
||||||
|
|
||||||
namespace Lantean.QBTMudBlade.Pages
|
namespace Lantean.QBTMudBlade.Pages
|
||||||
{
|
{
|
||||||
public partial class Blocks
|
public partial class Blocks : IAsyncDisposable
|
||||||
{
|
{
|
||||||
|
private readonly bool _refreshEnabled = true;
|
||||||
|
private const string _selectedTypesStorageKey = "Blocks.SelectedTypes";
|
||||||
|
|
||||||
|
private readonly CancellationTokenSource _timerCancellationToken = new();
|
||||||
|
private bool _disposedValue;
|
||||||
|
|
||||||
[Inject]
|
[Inject]
|
||||||
protected IApiClient ApiClient { get; set; } = default!;
|
protected IApiClient ApiClient { get; set; } = default!;
|
||||||
|
|
||||||
@@ -16,24 +25,129 @@ namespace Lantean.QBTMudBlade.Pages
|
|||||||
[Inject]
|
[Inject]
|
||||||
protected NavigationManager NavigationManager { get; set; } = default!;
|
protected NavigationManager NavigationManager { get; set; } = default!;
|
||||||
|
|
||||||
[CascadingParameter]
|
[Inject]
|
||||||
public MainData? MainData { get; set; }
|
protected ILocalStorageService LocalStorage { get; set; } = default!;
|
||||||
|
|
||||||
[CascadingParameter(Name = "DrawerOpen")]
|
[CascadingParameter(Name = "DrawerOpen")]
|
||||||
public bool DrawerOpen { get; set; }
|
public bool DrawerOpen { get; set; }
|
||||||
|
|
||||||
[Parameter]
|
protected LogForm Model { get; set; } = new LogForm();
|
||||||
public string? Hash { get; set; }
|
|
||||||
|
|
||||||
protected int ActiveTab { get; set; } = 0;
|
protected List<QBitTorrentClient.Models.PeerLog>? Results { get; private set; }
|
||||||
|
|
||||||
protected int RefreshInterval => MainData?.ServerState.RefreshInterval ?? 1500;
|
protected MudSelect<string>? CategoryMudSelect { get; set; }
|
||||||
|
|
||||||
protected ServerState? ServerState => MainData?.ServerState;
|
protected override async Task OnInitializedAsync()
|
||||||
|
{
|
||||||
|
var selectedTypes = await LocalStorage.GetItemAsync<IEnumerable<string>>(_selectedTypesStorageKey);
|
||||||
|
if (selectedTypes is not null)
|
||||||
|
{
|
||||||
|
Model.SelectedTypes = selectedTypes;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Model.SelectedTypes = ["Normal"];
|
||||||
|
}
|
||||||
|
|
||||||
|
await DoSearch();
|
||||||
|
}
|
||||||
|
|
||||||
protected void NavigateBack()
|
protected void NavigateBack()
|
||||||
{
|
{
|
||||||
NavigationManager.NavigateTo("/");
|
NavigationManager.NavigateTo("/");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected async Task SelectedValuesChanged(IEnumerable<string> values)
|
||||||
|
{
|
||||||
|
Model.SelectedTypes = values;
|
||||||
|
|
||||||
|
await LocalStorage.SetItemAsync(_selectedTypesStorageKey, Model.SelectedTypes);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static string GenerateSelectedText(List<string> values)
|
||||||
|
{
|
||||||
|
if (values.Count == 4)
|
||||||
|
{
|
||||||
|
return "All";
|
||||||
|
}
|
||||||
|
|
||||||
|
return $"{values.Count} selected";
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Task Submit(EditContext editContext)
|
||||||
|
{
|
||||||
|
return DoSearch();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task DoSearch()
|
||||||
|
{
|
||||||
|
var results = await ApiClient.GetPeerLog(Model.LastKnownId);
|
||||||
|
if (results.Count > 0)
|
||||||
|
{
|
||||||
|
Results ??= [];
|
||||||
|
Results.AddRange(results);
|
||||||
|
Model.LastKnownId = results[^1].Id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static string RowClass(QBitTorrentClient.Models.PeerLog log, int index)
|
||||||
|
{
|
||||||
|
return $"log-{(log.Blocked ? "critical" : "normal")}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask DisposeAsync()
|
||||||
|
{
|
||||||
|
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
|
||||||
|
await DisposeAsync(disposing: true);
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual async Task DisposeAsync(bool disposing)
|
||||||
|
{
|
||||||
|
if (!_disposedValue)
|
||||||
|
{
|
||||||
|
if (disposing)
|
||||||
|
{
|
||||||
|
_timerCancellationToken.Cancel();
|
||||||
|
_timerCancellationToken.Dispose();
|
||||||
|
|
||||||
|
await Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
_disposedValue = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||||
|
{
|
||||||
|
if (!_refreshEnabled)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!firstRender)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
using (var timer = new PeriodicTimer(TimeSpan.FromMilliseconds(1500)))
|
||||||
|
{
|
||||||
|
while (!_timerCancellationToken.IsCancellationRequested && await timer.WaitForNextTickAsync())
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await DoSearch();
|
||||||
|
}
|
||||||
|
catch (HttpRequestException exception) when (exception.StatusCode == HttpStatusCode.Forbidden || exception.StatusCode == HttpStatusCode.NotFound)
|
||||||
|
{
|
||||||
|
_timerCancellationToken.CancelIfNotDisposed();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await InvokeAsync(StateHasChanged);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
@page "/details/{hash}"
|
@page "/details/{hash}"
|
||||||
@layout DetailsLayout
|
@layout DetailsLayout
|
||||||
|
|
||||||
<MudToolBar DisableGutters="true" Dense="true">
|
<MudToolBar Gutters="false" Dense="true">
|
||||||
@if (!DrawerOpen)
|
@if (!DrawerOpen)
|
||||||
{
|
{
|
||||||
<MudIconButton Icon="@Icons.Material.Outlined.NavigateBefore" OnClick="NavigateBack" Title="Back to torrent list" />
|
<MudIconButton Icon="@Icons.Material.Outlined.NavigateBefore" OnClick="NavigateBack" title="Back to torrent list" />
|
||||||
<MudDivider Vertical="true" />
|
<MudDivider Vertical="true" />
|
||||||
}
|
}
|
||||||
@if (Hash is not null)
|
@if (Hash is not null)
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
@if (ShowTabs)
|
@if (ShowTabs)
|
||||||
{
|
{
|
||||||
<CascadingValue Value="RefreshInterval">
|
<CascadingValue Value="RefreshInterval" Name="RefreshInterval">
|
||||||
<MudTabs Elevation="2" ApplyEffectsToContainer="true" @bind-ActivePanelIndex="ActiveTab" KeepPanelsAlive="true" Border="true">
|
<MudTabs Elevation="2" ApplyEffectsToContainer="true" @bind-ActivePanelIndex="ActiveTab" KeepPanelsAlive="true" Border="true">
|
||||||
<MudTabPanel Text="General">
|
<MudTabPanel Text="General">
|
||||||
<GeneralTab Hash="@Hash" Active="@(ActiveTab == 0)" />
|
<GeneralTab Hash="@Hash" Active="@(ActiveTab == 0)" />
|
||||||
|
|||||||
@@ -1,16 +1,65 @@
|
|||||||
@page "/log"
|
@page "/log"
|
||||||
@layout OtherLayout
|
@layout OtherLayout
|
||||||
|
|
||||||
<MudToolBar DisableGutters="true" Dense="true">
|
<MudToolBar Gutters="false" Dense="true">
|
||||||
@if (!DrawerOpen)
|
@if (!DrawerOpen)
|
||||||
{
|
{
|
||||||
<MudIconButton Icon="@Icons.Material.Outlined.NavigateBefore" OnClick="NavigateBack" Title="Back to torrent list" />
|
<MudIconButton Icon="@Icons.Material.Outlined.NavigateBefore" OnClick="NavigateBack" title="Back to torrent list" />
|
||||||
<MudDivider Vertical="true" />
|
<MudDivider Vertical="true" />
|
||||||
}
|
}
|
||||||
<MudDivider Vertical="true" />
|
<MudDivider Vertical="true" />
|
||||||
<MudText Class="pl-5 no-wrap">Execution Log</MudText>
|
<MudText Class="pl-5 no-wrap">Execution Log</MudText>
|
||||||
</MudToolBar>
|
</MudToolBar>
|
||||||
|
|
||||||
<MudContainer MaxWidth="MaxWidth.ExtraExtraLarge" Class="details-tab-contents">
|
<MudCard Elevation="1" Class="ml-4 mr-4 mb-4">
|
||||||
<p>Coming soon.</p>
|
<MudCardContent>
|
||||||
</MudContainer>
|
<EditForm Model="Model" OnSubmit="Submit">
|
||||||
|
<MudGrid>
|
||||||
|
<MudItem md="8">
|
||||||
|
<MudTextField T="string" Label="Criteria" @bind-Value="Model.Criteria" ShrinkLabel Variant="Variant.Outlined" />
|
||||||
|
</MudItem>
|
||||||
|
<MudItem md="2">
|
||||||
|
<MudSelect @ref="CategoryMudSelect" T="string" Label="Categories" SelectedValues="Model.SelectedTypes" SelectedValuesChanged="SelectedValuesChanged" ShrinkLabel Variant="Variant.Outlined" MultiSelection="true" MultiSelectionTextFunc="GenerateSelectedText" SelectAll="true">
|
||||||
|
<MudSelectItem Value="@("Normal")">Normal</MudSelectItem>
|
||||||
|
<MudSelectItem Value="@("Info")">Info</MudSelectItem>
|
||||||
|
<MudSelectItem Value="@("Warning")">Warning</MudSelectItem>
|
||||||
|
<MudSelectItem Value="@("Critical")">Critical</MudSelectItem>
|
||||||
|
</MudSelect>
|
||||||
|
</MudItem>
|
||||||
|
<MudItem md="2">
|
||||||
|
<MudButton ButtonType="ButtonType.Submit" FullWidth="true" Color="Color.Primary" EndIcon="@Icons.Material.Filled.Search" Variant="Variant.Filled" Class="mt-6">Filter</MudButton>
|
||||||
|
</MudItem>
|
||||||
|
</MudGrid>
|
||||||
|
</EditForm>
|
||||||
|
</MudCardContent>
|
||||||
|
</MudCard>
|
||||||
|
|
||||||
|
<MudTable Items="Results"
|
||||||
|
T="Lantean.QBitTorrentClient.Models.Log"
|
||||||
|
Hover="true"
|
||||||
|
FixedHeader="true"
|
||||||
|
HeaderClass="table-head-bordered"
|
||||||
|
Dense="true"
|
||||||
|
Breakpoint="Breakpoint.None"
|
||||||
|
Bordered="true"
|
||||||
|
Square="true"
|
||||||
|
LoadingProgressColor="Color.Info"
|
||||||
|
HorizontalScrollbar="true"
|
||||||
|
Virtualize="true"
|
||||||
|
AllowUnsorted="false"
|
||||||
|
SelectOnRowClick="false"
|
||||||
|
Class="search-list"
|
||||||
|
RowClassFunc="RowClass">
|
||||||
|
<HeaderContent>
|
||||||
|
<MudTh>Id</MudTh>
|
||||||
|
<MudTh>Message</MudTh>
|
||||||
|
<MudTh>Timestamp</MudTh>
|
||||||
|
<MudTh>Log Type</MudTh>
|
||||||
|
</HeaderContent>
|
||||||
|
<RowTemplate>
|
||||||
|
<MudTd DataLabel="Od">@context.Id</MudTd>
|
||||||
|
<MudTd DataLabel="Message">@context.Message</MudTd>
|
||||||
|
<MudTd DataLabel="Timestamp">@DisplayHelpers.DateTime(context.Timestamp)</MudTd>
|
||||||
|
<MudTd DataLabel="Log Type">@context.Type</MudTd>
|
||||||
|
</RowTemplate>
|
||||||
|
</MudTable>
|
||||||
|
|||||||
@@ -1,12 +1,21 @@
|
|||||||
using Lantean.QBitTorrentClient;
|
using Blazored.LocalStorage;
|
||||||
|
using Lantean.QBitTorrentClient;
|
||||||
using Lantean.QBTMudBlade.Models;
|
using Lantean.QBTMudBlade.Models;
|
||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
|
using Microsoft.AspNetCore.Components.Forms;
|
||||||
using MudBlazor;
|
using MudBlazor;
|
||||||
|
using System.Net;
|
||||||
|
|
||||||
namespace Lantean.QBTMudBlade.Pages
|
namespace Lantean.QBTMudBlade.Pages
|
||||||
{
|
{
|
||||||
public partial class Log
|
public partial class Log : IAsyncDisposable
|
||||||
{
|
{
|
||||||
|
private readonly bool _refreshEnabled = true;
|
||||||
|
private const string _selectedTypesStorageKey = "Log.SelectedTypes";
|
||||||
|
|
||||||
|
private readonly CancellationTokenSource _timerCancellationToken = new();
|
||||||
|
private bool _disposedValue;
|
||||||
|
|
||||||
[Inject]
|
[Inject]
|
||||||
protected IApiClient ApiClient { get; set; } = default!;
|
protected IApiClient ApiClient { get; set; } = default!;
|
||||||
|
|
||||||
@@ -16,24 +25,129 @@ namespace Lantean.QBTMudBlade.Pages
|
|||||||
[Inject]
|
[Inject]
|
||||||
protected NavigationManager NavigationManager { get; set; } = default!;
|
protected NavigationManager NavigationManager { get; set; } = default!;
|
||||||
|
|
||||||
[CascadingParameter]
|
[Inject]
|
||||||
public MainData? MainData { get; set; }
|
protected ILocalStorageService LocalStorage { get; set; } = default!;
|
||||||
|
|
||||||
[CascadingParameter(Name = "DrawerOpen")]
|
[CascadingParameter(Name = "DrawerOpen")]
|
||||||
public bool DrawerOpen { get; set; }
|
public bool DrawerOpen { get; set; }
|
||||||
|
|
||||||
[Parameter]
|
protected LogForm Model { get; set; } = new LogForm();
|
||||||
public string? Hash { get; set; }
|
|
||||||
|
|
||||||
protected int ActiveTab { get; set; } = 0;
|
protected List<QBitTorrentClient.Models.Log>? Results { get; private set; }
|
||||||
|
|
||||||
protected int RefreshInterval => MainData?.ServerState.RefreshInterval ?? 1500;
|
protected MudSelect<string>? CategoryMudSelect { get; set; }
|
||||||
|
|
||||||
protected ServerState? ServerState => MainData?.ServerState;
|
protected override async Task OnInitializedAsync()
|
||||||
|
{
|
||||||
|
var selectedTypes = await LocalStorage.GetItemAsync<IEnumerable<string>>(_selectedTypesStorageKey);
|
||||||
|
if (selectedTypes is not null)
|
||||||
|
{
|
||||||
|
Model.SelectedTypes = selectedTypes;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Model.SelectedTypes = ["Normal"];
|
||||||
|
}
|
||||||
|
|
||||||
|
await DoSearch();
|
||||||
|
}
|
||||||
|
|
||||||
protected void NavigateBack()
|
protected void NavigateBack()
|
||||||
{
|
{
|
||||||
NavigationManager.NavigateTo("/");
|
NavigationManager.NavigateTo("/");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected async Task SelectedValuesChanged(IEnumerable<string> values)
|
||||||
|
{
|
||||||
|
Model.SelectedTypes = values;
|
||||||
|
|
||||||
|
await LocalStorage.SetItemAsync(_selectedTypesStorageKey, Model.SelectedTypes);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static string GenerateSelectedText(List<string> values)
|
||||||
|
{
|
||||||
|
if (values.Count == 4)
|
||||||
|
{
|
||||||
|
return "All";
|
||||||
|
}
|
||||||
|
|
||||||
|
return $"{values.Count} selected";
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Task Submit(EditContext editContext)
|
||||||
|
{
|
||||||
|
return DoSearch();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task DoSearch()
|
||||||
|
{
|
||||||
|
var results = await ApiClient.GetLog(Model.Normal, Model.Info, Model.Warning, Model.Critical, Model.LastKnownId);
|
||||||
|
if (results.Count > 0)
|
||||||
|
{
|
||||||
|
Results ??= [];
|
||||||
|
Results.AddRange(results);
|
||||||
|
Model.LastKnownId = results[^1].Id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static string RowClass(QBitTorrentClient.Models.Log log, int index)
|
||||||
|
{
|
||||||
|
return $"log-{log.Type.ToString().ToLower()}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask DisposeAsync()
|
||||||
|
{
|
||||||
|
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
|
||||||
|
await DisposeAsync(disposing: true);
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual async Task DisposeAsync(bool disposing)
|
||||||
|
{
|
||||||
|
if (!_disposedValue)
|
||||||
|
{
|
||||||
|
if (disposing)
|
||||||
|
{
|
||||||
|
_timerCancellationToken.Cancel();
|
||||||
|
_timerCancellationToken.Dispose();
|
||||||
|
|
||||||
|
await Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
_disposedValue = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||||
|
{
|
||||||
|
if (!_refreshEnabled)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!firstRender)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
using (var timer = new PeriodicTimer(TimeSpan.FromMilliseconds(1500)))
|
||||||
|
{
|
||||||
|
while (!_timerCancellationToken.IsCancellationRequested && await timer.WaitForNextTickAsync())
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await DoSearch();
|
||||||
|
}
|
||||||
|
catch (HttpRequestException exception) when (exception.StatusCode == HttpStatusCode.Forbidden || exception.StatusCode == HttpStatusCode.NotFound)
|
||||||
|
{
|
||||||
|
_timerCancellationToken.CancelIfNotDisposed();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await InvokeAsync(StateHasChanged);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,7 @@
|
|||||||
using Lantean.QBitTorrentClient;
|
using Lantean.QBitTorrentClient;
|
||||||
|
using Lantean.QBTMudBlade.Models;
|
||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
using Microsoft.AspNetCore.Components.Forms;
|
using Microsoft.AspNetCore.Components.Forms;
|
||||||
using System.ComponentModel.DataAnnotations;
|
|
||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
|
||||||
namespace Lantean.QBTMudBlade.Pages
|
namespace Lantean.QBTMudBlade.Pages
|
||||||
@@ -15,7 +14,7 @@ namespace Lantean.QBTMudBlade.Pages
|
|||||||
[Inject]
|
[Inject]
|
||||||
protected NavigationManager NavigationManager { get; set; } = default!;
|
protected NavigationManager NavigationManager { get; set; } = default!;
|
||||||
|
|
||||||
protected LoginModel Model { get; set; } = new LoginModel();
|
protected LoginForm Model { get; set; } = new LoginForm();
|
||||||
|
|
||||||
protected string? ApiError { get; set; }
|
protected string? ApiError { get; set; }
|
||||||
|
|
||||||
@@ -49,19 +48,8 @@ namespace Lantean.QBTMudBlade.Pages
|
|||||||
#if DEBUG
|
#if DEBUG
|
||||||
protected override Task OnInitializedAsync()
|
protected override Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
return DoLogin("admin", "6K3mtPNnQ");
|
return DoLogin("admin", "STMeVwB22");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
public class LoginModel
|
|
||||||
{
|
|
||||||
[Required]
|
|
||||||
[NotNull]
|
|
||||||
public string? Username { get; set; }
|
|
||||||
|
|
||||||
[Required]
|
|
||||||
[NotNull]
|
|
||||||
public string? Password { get; set; }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
<NavigationLock ConfirmExternalNavigation="@(UpdatePreferences is not null)" OnBeforeInternalNavigation="ValidateExit" />
|
<NavigationLock ConfirmExternalNavigation="@(UpdatePreferences is not null)" OnBeforeInternalNavigation="ValidateExit" />
|
||||||
|
|
||||||
<MudToolBar DisableGutters="true" Dense="true">
|
<MudToolBar Gutters="false" Dense="true">
|
||||||
@if (!DrawerOpen)
|
@if (!DrawerOpen)
|
||||||
{
|
{
|
||||||
<MudIconButton Icon="@Icons.Material.Outlined.NavigateBefore" OnClick="NavigateBack" />
|
<MudIconButton Icon="@Icons.Material.Outlined.NavigateBefore" OnClick="NavigateBack" />
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
@page "/rss"
|
@page "/rss"
|
||||||
@layout OtherLayout
|
@layout OtherLayout
|
||||||
|
|
||||||
<MudToolBar DisableGutters="true" Dense="true">
|
<MudToolBar Gutters="false" Dense="true">
|
||||||
@if (!DrawerOpen)
|
@if (!DrawerOpen)
|
||||||
{
|
{
|
||||||
<MudIconButton Icon="@Icons.Material.Outlined.NavigateBefore" OnClick="NavigateBack" Title="Back to torrent list" />
|
<MudIconButton Icon="@Icons.Material.Outlined.NavigateBefore" OnClick="NavigateBack" title="Back to torrent list" />
|
||||||
<MudDivider Vertical="true" />
|
<MudDivider Vertical="true" />
|
||||||
}
|
}
|
||||||
<MudDivider Vertical="true" />
|
<MudDivider Vertical="true" />
|
||||||
|
|||||||
@@ -1,49 +1,51 @@
|
|||||||
@page "/search"
|
@page "/search"
|
||||||
@layout OtherLayout
|
@layout OtherLayout
|
||||||
|
|
||||||
<MudToolBar DisableGutters="true" Dense="true">
|
<MudToolBar Gutters="false" Dense="true">
|
||||||
@if (!DrawerOpen)
|
@if (!DrawerOpen)
|
||||||
{
|
{
|
||||||
<MudIconButton Icon="@Icons.Material.Outlined.NavigateBefore" OnClick="NavigateBack" Title="Back to torrent list" />
|
<MudIconButton Icon="@Icons.Material.Outlined.NavigateBefore" OnClick="NavigateBack" title="Back to torrent list" />
|
||||||
<MudDivider Vertical="true" />
|
<MudDivider Vertical="true" />
|
||||||
}
|
}
|
||||||
<MudDivider Vertical="true" />
|
<MudDivider Vertical="true" />
|
||||||
<MudText Class="pl-5 no-wrap">Search</MudText>
|
<MudText Class="pl-5 no-wrap">Search</MudText>
|
||||||
</MudToolBar>
|
</MudToolBar>
|
||||||
|
|
||||||
<MudCard Elevation="1" Class="ml-4 mr-4 mb-4 mt-4">
|
<MudCard Elevation="1" Class="ml-4 mr-4 mb-4">
|
||||||
<MudCardContent Class="pt-0">
|
<MudCardContent>
|
||||||
<MudGrid>
|
<EditForm Model="Model" OnValidSubmit="DoSearch">
|
||||||
<MudItem xs="12" md="6">
|
<MudGrid>
|
||||||
<MudTextField T="string" Label="Search" Value="SearchText" ValueChanged="SearchTextChanged" ShrinkLabel Variant="Variant.Outlined" />
|
<MudItem xs="12" md="6">
|
||||||
</MudItem>
|
<MudTextField T="string" Label="Criteria" @bind-Value="Model.SearchText" ShrinkLabel Variant="Variant.Outlined" />
|
||||||
<MudItem md="2">
|
</MudItem>
|
||||||
<MudSelect T="string" Label="Categories" Value="SelectedCategory" ValueChanged="SelectedCategoryChanged" ShrinkLabel Variant="Variant.Outlined">
|
<MudItem md="2">
|
||||||
@foreach (var (value, name) in Categories)
|
<MudSelect T="string" Label="Categories" @bind-Value="Model.SelectedCategory" ShrinkLabel Variant="Variant.Outlined">
|
||||||
{
|
@foreach (var (value, name) in Categories)
|
||||||
<MudSelectItem Value="value">@name</MudSelectItem>
|
|
||||||
if (value == "all")
|
|
||||||
{
|
{
|
||||||
<MudDivider />
|
<MudSelectItem Value="value">@name</MudSelectItem>
|
||||||
|
if (value == "all")
|
||||||
|
{
|
||||||
|
<MudDivider />
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
</MudSelect>
|
||||||
</MudSelect>
|
</MudItem>
|
||||||
</MudItem>
|
<MudItem md="2">
|
||||||
<MudItem md="2">
|
<MudSelect T="string" Label="Plugins" @bind-Value="Model.SelectedPlugin" ShrinkLabel Variant="Variant.Outlined">
|
||||||
<MudSelect T="string" Label="Plugins" Value="SelectedPlugin" ValueChanged="SelectedPluginChanged" ShrinkLabel Variant="Variant.Outlined">
|
<MudSelectItem Value="@("all")">All</MudSelectItem>
|
||||||
<MudSelectItem Value="@("all")">All</MudSelectItem>
|
<MudDivider />
|
||||||
<MudDivider />
|
@foreach (var (value, name) in Plugins)
|
||||||
@foreach (var (value, name) in Plugins)
|
{
|
||||||
{
|
<MudSelectItem Value="value">@name</MudSelectItem>
|
||||||
<MudSelectItem Value="value">@name</MudSelectItem>
|
}
|
||||||
}
|
</MudSelect>
|
||||||
</MudSelect>
|
</MudItem>
|
||||||
</MudItem>
|
<MudItem md="2">
|
||||||
<MudItem md="2">
|
<MudButton ButtonType="ButtonType.Submit" FullWidth="true" Color="Color.Primary" EndIcon="@Icons.Material.Filled.Search" Variant="Variant.Filled" Class="mt-6">@(_searchId is null ? "Search" : "Stop")</MudButton>
|
||||||
<MudButton OnClick="DoSearch" FullWidth="true" Variant="Variant.Outlined">@(_searchId is null ? "Search" : "Stop")</MudButton>
|
</MudItem>
|
||||||
</MudItem>
|
|
||||||
|
|
||||||
</MudGrid>
|
</MudGrid>
|
||||||
|
</EditForm>
|
||||||
</MudCardContent>
|
</MudCardContent>
|
||||||
</MudCard>
|
</MudCard>
|
||||||
|
|
||||||
@@ -62,7 +64,7 @@
|
|||||||
Virtualize="true"
|
Virtualize="true"
|
||||||
AllowUnsorted="false"
|
AllowUnsorted="false"
|
||||||
SelectOnRowClick="false"
|
SelectOnRowClick="false"
|
||||||
Class="details-list">
|
Class="search-list">
|
||||||
<HeaderContent>
|
<HeaderContent>
|
||||||
<MudTh>Name</MudTh>
|
<MudTh>Name</MudTh>
|
||||||
<MudTh>Size</MudTh>
|
<MudTh>Size</MudTh>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using Lantean.QBitTorrentClient;
|
using Lantean.QBitTorrentClient;
|
||||||
using Lantean.QBTMudBlade.Models;
|
using Lantean.QBTMudBlade.Models;
|
||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
|
using Microsoft.AspNetCore.Components.Forms;
|
||||||
using MudBlazor;
|
using MudBlazor;
|
||||||
|
|
||||||
namespace Lantean.QBTMudBlade.Pages
|
namespace Lantean.QBTMudBlade.Pages
|
||||||
@@ -33,21 +34,11 @@ namespace Lantean.QBTMudBlade.Pages
|
|||||||
[Parameter]
|
[Parameter]
|
||||||
public string? Hash { get; set; }
|
public string? Hash { get; set; }
|
||||||
|
|
||||||
protected int ActiveTab { get; set; } = 0;
|
protected SearchForm Model { get; set; } = new SearchForm();
|
||||||
|
|
||||||
protected int RefreshInterval => MainData?.ServerState.RefreshInterval ?? 1500;
|
|
||||||
|
|
||||||
protected ServerState? ServerState => MainData?.ServerState;
|
|
||||||
|
|
||||||
protected string? SearchText { get; set; }
|
|
||||||
|
|
||||||
protected string SelectedPlugin { get; set; } = "all";
|
|
||||||
|
|
||||||
protected string SelectedCategory { get; set; } = "all";
|
|
||||||
|
|
||||||
protected Dictionary<string, string> Plugins => _plugins is null ? [] : _plugins.ToDictionary(a => a.Name, a => a.FullName);
|
protected Dictionary<string, string> Plugins => _plugins is null ? [] : _plugins.ToDictionary(a => a.Name, a => a.FullName);
|
||||||
|
|
||||||
protected Dictionary<string, string> Categories => GetCategories(SelectedPlugin);
|
protected Dictionary<string, string> Categories => GetCategories(Model.SelectedPlugin);
|
||||||
|
|
||||||
protected IEnumerable<QBitTorrentClient.Models.SearchResult>? Results => _searchResults?.Results;
|
protected IEnumerable<QBitTorrentClient.Models.SearchResult>? Results => _searchResults?.Results;
|
||||||
|
|
||||||
@@ -97,21 +88,6 @@ namespace Lantean.QBTMudBlade.Pages
|
|||||||
NavigationManager.NavigateTo("/");
|
NavigationManager.NavigateTo("/");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void SearchTextChanged(string value)
|
|
||||||
{
|
|
||||||
SearchText = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void SelectedCategoryChanged(string value)
|
|
||||||
{
|
|
||||||
SelectedCategory = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void SelectedPluginChanged(string value)
|
|
||||||
{
|
|
||||||
SelectedPlugin = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Dictionary<string, string> GetCategories(string plugin)
|
private Dictionary<string, string> GetCategories(string plugin)
|
||||||
{
|
{
|
||||||
if (_plugins is null)
|
if (_plugins is null)
|
||||||
@@ -133,17 +109,17 @@ namespace Lantean.QBTMudBlade.Pages
|
|||||||
return pluginItem.SupportedCategories.ToDictionary(a => a.Id, a => a.Name);
|
return pluginItem.SupportedCategories.ToDictionary(a => a.Id, a => a.Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async Task DoSearch()
|
protected async Task DoSearch(EditContext editContext)
|
||||||
{
|
{
|
||||||
if (_searchId is null)
|
if (_searchId is null)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(SearchText))
|
if (string.IsNullOrEmpty(Model.SearchText))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_searchResults = null;
|
_searchResults = null;
|
||||||
_searchId = await ApiClient.StartSearch(SearchText, [SelectedPlugin], SelectedCategory);
|
_searchId = await ApiClient.StartSearch(Model.SearchText, [Model.SelectedPlugin], Model.SelectedCategory);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
@page "/statistics"
|
@page "/statistics"
|
||||||
@layout OtherLayout
|
@layout OtherLayout
|
||||||
|
|
||||||
<MudToolBar DisableGutters="true" Dense="true">
|
<MudToolBar Gutters="false" Dense="true">
|
||||||
@if (!DrawerOpen)
|
@if (!DrawerOpen)
|
||||||
{
|
{
|
||||||
<MudIconButton Icon="@Icons.Material.Outlined.NavigateBefore" OnClick="NavigateBack" Title="Back to torrent list" />
|
<MudIconButton Icon="@Icons.Material.Outlined.NavigateBefore" OnClick="NavigateBack" title="Back to torrent list" />
|
||||||
<MudDivider Vertical="true" />
|
<MudDivider Vertical="true" />
|
||||||
}
|
}
|
||||||
<MudDivider Vertical="true" />
|
<MudDivider Vertical="true" />
|
||||||
|
|||||||
@@ -22,13 +22,14 @@ namespace Lantean.QBTMudBlade.Pages
|
|||||||
[CascadingParameter(Name = "DrawerOpen")]
|
[CascadingParameter(Name = "DrawerOpen")]
|
||||||
public bool DrawerOpen { get; set; }
|
public bool DrawerOpen { get; set; }
|
||||||
|
|
||||||
|
[CascadingParameter(Name = "RefreshInterval")]
|
||||||
|
public int RefreshInterval { get; set; }
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public string? Hash { get; set; }
|
public string? Hash { get; set; }
|
||||||
|
|
||||||
protected int ActiveTab { get; set; } = 0;
|
protected int ActiveTab { get; set; } = 0;
|
||||||
|
|
||||||
protected int RefreshInterval => MainData?.ServerState.RefreshInterval ?? 1500;
|
|
||||||
|
|
||||||
protected ServerState? ServerState => MainData?.ServerState;
|
protected ServerState? ServerState => MainData?.ServerState;
|
||||||
|
|
||||||
protected void NavigateBack()
|
protected void NavigateBack()
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
@page "/"
|
@page "/"
|
||||||
@layout ListLayout
|
@layout ListLayout
|
||||||
|
|
||||||
<MudToolBar DisableGutters="true" Dense="true">
|
<MudToolBar Gutters="false" Dense="true">
|
||||||
<MudIconButton Icon="@Icons.Material.Outlined.AddLink" OnClick="AddTorrentLink" Title="Add torrent link" />
|
<MudIconButton Icon="@Icons.Material.Outlined.AddLink" OnClick="AddTorrentLink" title="Add torrent link" />
|
||||||
<MudIconButton Icon="@Icons.Material.Outlined.AddCircle" OnClick="AddTorrentFile" Title="Add torrent file" />
|
<MudIconButton Icon="@Icons.Material.Outlined.AddCircle" OnClick="AddTorrentFile" title="Add torrent file" />
|
||||||
<MudDivider Vertical="true" />
|
<MudDivider Vertical="true" />
|
||||||
<TorrentActions RenderType="RenderType.InitialIconsOnly" Hashes="GetSelectedTorrents()" />
|
<TorrentActions RenderType="RenderType.InitialIconsOnly" Hashes="GetSelectedTorrents()" />
|
||||||
<MudDivider Vertical="true" />
|
<MudDivider Vertical="true" />
|
||||||
<MudIconButton Icon="@Icons.Material.Outlined.Info" Color="Color.Inherit" Disabled="@(!ToolbarButtonsEnabled)" OnClick="ShowTorrent" Title="View torrent details" />
|
<MudIconButton Icon="@Icons.Material.Outlined.Info" Color="Color.Inherit" Disabled="@(!ToolbarButtonsEnabled)" OnClick="ShowTorrent" title="View torrent details" />
|
||||||
<MudIconButton Icon="@Icons.Material.Outlined.ViewColumn" Color="Color.Inherit" OnClick="ColumnOptions" Title="Choose Columns" />
|
<MudIconButton Icon="@Icons.Material.Outlined.ViewColumn" Color="Color.Inherit" OnClick="ColumnOptions" title="Choose Columns" />
|
||||||
<MudSpacer />
|
<MudSpacer />
|
||||||
<MudTextField Value="SearchText" TextChanged="SearchTextChanged" Immediate="true" DebounceInterval="1000" Placeholder="Filter torrent list" Adornment="Adornment.Start" AdornmentIcon="@Icons.Material.Filled.Search" IconSize="Size.Medium" Class="mt-0"></MudTextField>
|
<MudTextField Value="SearchText" TextChanged="SearchTextChanged" Immediate="true" DebounceInterval="1000" Placeholder="Filter torrent list" Adornment="Adornment.Start" AdornmentIcon="@Icons.Material.Filled.Search" IconSize="Size.Medium" Class="mt-0"></MudTextField>
|
||||||
</MudToolBar>
|
</MudToolBar>
|
||||||
|
|||||||
@@ -170,4 +170,24 @@ td.no-wrap {
|
|||||||
.details-tab-contents {
|
.details-tab-contents {
|
||||||
height: calc(100vh - 200px);
|
height: calc(100vh - 200px);
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-list .mud-table-container {
|
||||||
|
height: calc(100vh - 260px);
|
||||||
|
}
|
||||||
|
|
||||||
|
tr.log-normal td {
|
||||||
|
color: var(--mud-palette-text-primary) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr.log-info td {
|
||||||
|
color: var(--mud-palette-info) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr.log-warning td {
|
||||||
|
color: var(--mud-palette-warning) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr.log-critical td {
|
||||||
|
color: var(--mud-palette-error) !important;
|
||||||
}
|
}
|
||||||
@@ -887,10 +887,10 @@ namespace Lantean.QBitTorrentClient
|
|||||||
{
|
{
|
||||||
var content = new FormUrlEncodedBuilder()
|
var content = new FormUrlEncodedBuilder()
|
||||||
.AddAllOrPipeSeparated("hashes", all, hashes)
|
.AddAllOrPipeSeparated("hashes", all, hashes)
|
||||||
.Add("enable", value)
|
.Add("value", value)
|
||||||
.ToFormUrlEncodedContent();
|
.ToFormUrlEncodedContent();
|
||||||
|
|
||||||
var response = await _httpClient.PostAsync("torrents/setFOrceStart", content);
|
var response = await _httpClient.PostAsync("torrents/setForceStart", content);
|
||||||
|
|
||||||
response.EnsureSuccessStatusCode();
|
response.EnsureSuccessStatusCode();
|
||||||
}
|
}
|
||||||
@@ -1105,16 +1105,30 @@ namespace Lantean.QBitTorrentClient
|
|||||||
|
|
||||||
private async Task<IReadOnlyList<T>> GetJsonList<T>(HttpContent content)
|
private async Task<IReadOnlyList<T>> GetJsonList<T>(HttpContent content)
|
||||||
{
|
{
|
||||||
var items = await GetJson<IEnumerable<T>>(content);
|
try
|
||||||
|
{
|
||||||
|
var items = await GetJson<IEnumerable<T>>(content);
|
||||||
|
|
||||||
return items.ToList().AsReadOnly();
|
return items.ToList().AsReadOnly();
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<IReadOnlyDictionary<TKey, TValue>> GetJsonDictionary<TKey, TValue>(HttpContent content) where TKey : notnull
|
private async Task<IReadOnlyDictionary<TKey, TValue>> GetJsonDictionary<TKey, TValue>(HttpContent content) where TKey : notnull
|
||||||
{
|
{
|
||||||
var items = await GetJson<IDictionary<TKey, TValue>>(content);
|
try
|
||||||
|
{
|
||||||
|
var items = await GetJson<IDictionary<TKey, TValue>>(content);
|
||||||
|
|
||||||
return items.AsReadOnly();
|
return items.AsReadOnly();
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return new Dictionary<TKey, TValue>().AsReadOnly();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user