mirror of
https://github.com/lantean-code/qbtmud.git
synced 2025-11-02 04:53:19 +00:00
Rework actions to mirror original implmentation and add missing torrent actions
This commit is contained in:
@@ -22,34 +22,30 @@ else if (RenderType == RenderType.InitialIconsOnly)
|
|||||||
{
|
{
|
||||||
@foreach (var action in Actions.Take(5))
|
@foreach (var action in Actions.Take(5))
|
||||||
{
|
{
|
||||||
@if (action is Divider)
|
@if (action.SeparatorBefore)
|
||||||
{
|
{
|
||||||
<MudDivider Vertical="true" />
|
<MudDivider Vertical="true" />
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
<MudIconButton Title="@action.Text" Icon="@action.Icon" Color="action.Color" OnClick="action.Callback" Disabled="Disabled" />
|
||||||
<MudIconButton Title="@action.Name" Icon="@action.Icon" Color="action.Color" OnClick="action.Callback" Disabled="Disabled" />
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Menu(Actions.Skip(5))
|
@Menu(Actions.Skip(5))
|
||||||
}
|
}
|
||||||
else if (RenderType == RenderType.Children)
|
else if (RenderType == RenderType.Children)
|
||||||
{
|
{
|
||||||
var parent = Actions.FirstOrDefault(a => a.Name == ParentAction?.Name);
|
var parent = Actions.FirstOrDefault(a => a.Text == ParentAction?.Text);
|
||||||
if (parent is not null)
|
if (parent is not null)
|
||||||
{
|
{
|
||||||
<MudList Clickable="true">
|
<MudList Clickable="true">
|
||||||
@foreach (var action in parent.Children)
|
@foreach (var action in parent.Children)
|
||||||
{
|
{
|
||||||
@if (action is Divider)
|
@if (action.SeparatorBefore)
|
||||||
{
|
{
|
||||||
<MudDivider />
|
<MudDivider />
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
<MudListItem Icon="@action.Icon" IconColor="action.Color" OnClick="action.Callback" Disabled="Disabled">@action.Text</MudListItem>
|
||||||
<MudListItem Icon="@action.Icon" IconColor="action.Color" OnClick="action.Callback" Disabled="Disabled">@action.Name</MudListItem>
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</MudList>
|
</MudList>
|
||||||
}
|
}
|
||||||
@@ -68,24 +64,25 @@ else
|
|||||||
{
|
{
|
||||||
foreach (var action in Actions)
|
foreach (var action in Actions)
|
||||||
{
|
{
|
||||||
if (action is Divider)
|
if (action.SeparatorBefore)
|
||||||
{
|
{
|
||||||
<MudDivider Vertical="true" />
|
<MudDivider Vertical="true" />
|
||||||
}
|
}
|
||||||
else if (!action.Children.Any())
|
|
||||||
|
if (!action.Children.Any())
|
||||||
{
|
{
|
||||||
if (action.Icon is null)
|
if (action.Icon is null)
|
||||||
{
|
{
|
||||||
<MudButton Color="action.Color" OnClick="action.Callback">@action.Name</MudButton>
|
<MudButton Color="action.Color" OnClick="action.Callback">@action.Text</MudButton>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<MudIconButton Title="@action.Name" 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
|
||||||
{
|
{
|
||||||
<MudMenu Icon="@action.Icon" IconColor="@action.Color" Label="@action.Name" title="@action.Name" AnchorOrigin="Origin.BottomLeft" TransformOrigin="Origin.TopLeft">
|
<MudMenu Icon="@action.Icon" IconColor="@action.Color" Label="@action.Text" title="@action.Text" AnchorOrigin="Origin.BottomLeft" TransformOrigin="Origin.TopLeft">
|
||||||
@foreach (var childItem in action.Children)
|
@foreach (var childItem in action.Children)
|
||||||
{
|
{
|
||||||
@ChildItem(childItem)
|
@ChildItem(childItem)
|
||||||
@@ -105,24 +102,25 @@ else
|
|||||||
{
|
{
|
||||||
foreach (var action in Actions)
|
foreach (var action in Actions)
|
||||||
{
|
{
|
||||||
if (action is Divider)
|
if (action.SeparatorBefore)
|
||||||
{
|
{
|
||||||
<MudDivider Vertical="true" />
|
<MudDivider Vertical="true" />
|
||||||
}
|
}
|
||||||
else if (!action.Children.Any())
|
|
||||||
|
if (!action.Children.Any())
|
||||||
{
|
{
|
||||||
if (action.Icon is null)
|
if (action.Icon is null)
|
||||||
{
|
{
|
||||||
<MudButton Color="action.Color" OnClick="action.Callback" Disabled="Disabled">@action.Name</MudButton>
|
<MudButton Color="action.Color" OnClick="action.Callback" Disabled="Disabled">@action.Text</MudButton>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<MudIconButton Title="@action.Name" 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
|
||||||
{
|
{
|
||||||
<MudMenu Label="@action.Name" title="@action.Name" AnchorOrigin="Origin.BottomLeft" TransformOrigin="Origin.TopLeft" EndIcon="@Icons.Material.Filled.ArrowDropDown">
|
<MudMenu Label="@action.Text" title="@action.Text" AnchorOrigin="Origin.BottomLeft" TransformOrigin="Origin.TopLeft" EndIcon="@Icons.Material.Filled.ArrowDropDown">
|
||||||
@foreach (var childItem in action.Children)
|
@foreach (var childItem in action.Children)
|
||||||
{
|
{
|
||||||
@ChildItem(childItem)
|
@ChildItem(childItem)
|
||||||
@@ -138,14 +136,12 @@ else
|
|||||||
{
|
{
|
||||||
return __builder =>
|
return __builder =>
|
||||||
{
|
{
|
||||||
if (action is Divider)
|
if (action.SeparatorBefore)
|
||||||
{
|
{
|
||||||
<MudDivider />
|
<MudDivider />
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
<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" OnTouch="action.Callback" Disabled="Disabled">@action.Name</MudMenuItem>
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,14 +152,15 @@ else
|
|||||||
<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())">
|
||||||
@foreach (var action in actions)
|
@foreach (var action in actions)
|
||||||
{
|
{
|
||||||
@if (action is Divider)
|
@if (action.SeparatorBefore)
|
||||||
{
|
{
|
||||||
<MudDivider />
|
<MudDivider />
|
||||||
}
|
}
|
||||||
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" OnTouch="action.Callback" Disabled="Disabled">
|
||||||
@action.Name
|
@action.Text
|
||||||
</MudMenuItem>
|
</MudMenuItem>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -171,7 +168,7 @@ else
|
|||||||
<MudMenuItem Icon="@action.Icon" IconColor="action.Color" OnTouch="@(t => SubMenuTouch(action))" OnClick="@(t => SubMenuTouch(action))">
|
<MudMenuItem Icon="@action.Icon" IconColor="action.Color" OnTouch="@(t => SubMenuTouch(action))" 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" DisableElevation="true" DisableRipple="true" Class="sub-menu">
|
||||||
<ActivatorContent>
|
<ActivatorContent>
|
||||||
@action.Name
|
@action.Text
|
||||||
</ActivatorContent>
|
</ActivatorContent>
|
||||||
|
|
||||||
<ChildContent>
|
<ChildContent>
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ namespace Lantean.QBTMudBlade.Components
|
|||||||
{
|
{
|
||||||
public partial class TorrentActions
|
public partial class TorrentActions
|
||||||
{
|
{
|
||||||
|
private readonly List<TorrentAction> _actions;
|
||||||
|
|
||||||
[Inject]
|
[Inject]
|
||||||
public IApiClient ApiClient { get; set; } = default!;
|
public IApiClient ApiClient { get; set; } = default!;
|
||||||
|
|
||||||
@@ -58,6 +60,47 @@ namespace Lantean.QBTMudBlade.Components
|
|||||||
|
|
||||||
protected bool Disabled => !Hashes.Any();
|
protected bool Disabled => !Hashes.Any();
|
||||||
|
|
||||||
|
public TorrentActions()
|
||||||
|
{
|
||||||
|
_actions = new List<TorrentAction>
|
||||||
|
{
|
||||||
|
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("forceStart", "Force start", Icons.Material.Filled.Pause, Color.Warning, CreateCallback(ForceStart)),
|
||||||
|
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("rename", "Rename", Icons.Material.Filled.DriveFileRenameOutline, Color.Info, CreateCallback(Rename)),
|
||||||
|
new TorrentAction("renameFiles", "Rename files", Icons.Material.Filled.DriveFileRenameOutline, Color.Warning, CreateCallback(Rename)),
|
||||||
|
new TorrentAction("category", "Category", Icons.Material.Filled.List, Color.Info, CreateCallback(ShowCategories)),
|
||||||
|
new TorrentAction("tags", "Tags", Icons.Material.Filled.Label, Color.Info, CreateCallback(ShowTags)),
|
||||||
|
new TorrentAction("autoTorrentManagement", "Automatic Torrent Management", Icons.Material.Filled.Check, Color.Info, CreateCallback(ToggleAutoTMM)),
|
||||||
|
new TorrentAction("downloadLimit", "Limit download rate", Icons.Material.Filled.KeyboardDoubleArrowUp, Color.Info, CreateCallback(LimitDownloadRate), separatorBefore: true),
|
||||||
|
new TorrentAction("uploadLimit", "Limit upload rate", Icons.Material.Filled.KeyboardDoubleArrowUp, Color.Info, CreateCallback(LimitUploadRate)),
|
||||||
|
new TorrentAction("shareRatio", "Limit share ratio", Icons.Material.Filled.Percent, Color.Warning, CreateCallback(LimitShareRatio)),
|
||||||
|
new TorrentAction("superSeeding", "Super seeding mode", Icons.Material.Filled.Check, Color.Info, CreateCallback(ToggleSuperSeeding)),
|
||||||
|
new TorrentAction("sequentialDownload", "Download in sequential order", Icons.Material.Filled.Reorder, Color.Info, CreateCallback(DownloadSequential), separatorBefore: true),
|
||||||
|
new TorrentAction("firstLastPiecePrio", "Download first and last pieces first", Icons.Material.Filled.Navigation, Color.Info, CreateCallback(DownloadFirstLast)),
|
||||||
|
new TorrentAction("forceRecheck", "Force recheck", Icons.Material.Filled.Loop, Color.Info, CreateCallback(ForceRecheck), separatorBefore: true),
|
||||||
|
new TorrentAction("forceReannounce", "Force reannounce", Icons.Material.Filled.BroadcastOnHome, Color.Info, CreateCallback(ForceReannounce)),
|
||||||
|
new TorrentAction("queue", "Queue", Icons.Material.Filled.Queue, Color.Transparent, new List<TorrentAction>
|
||||||
|
{
|
||||||
|
new TorrentAction("queueTop", "Move to top", Icons.Material.Filled.VerticalAlignTop, Color.Inherit, CreateCallback(MoveToTop)),
|
||||||
|
new TorrentAction("queueUp", "Move up", Icons.Material.Filled.ArrowUpward, Color.Inherit, CreateCallback(MoveUp)),
|
||||||
|
new TorrentAction("queueDown", "Move down", Icons.Material.Filled.ArrowDownward, Color.Inherit, CreateCallback(MoveDown)),
|
||||||
|
new TorrentAction("queueBottom", "Move to bottom", Icons.Material.Filled.VerticalAlignBottom, Color.Inherit, CreateCallback(MoveToBottom)),
|
||||||
|
}, separatorBefore: true),
|
||||||
|
new TorrentAction("copy", "Copy", Icons.Material.Filled.FolderCopy, Color.Info, new List<TorrentAction>
|
||||||
|
{
|
||||||
|
new TorrentAction("copyName", "Name", Icons.Material.Filled.TextFields, Color.Info, CreateCallback(() => Copy(t => t.Name))),
|
||||||
|
new TorrentAction("copyHashv1", "Info hash v1", Icons.Material.Filled.Tag, Color.Info, CreateCallback(() => Copy(t => t.InfoHashV1))),
|
||||||
|
new TorrentAction("copyHashv2", "Info hash v2", Icons.Material.Filled.Tag, Color.Info, CreateCallback(() => Copy(t => t.InfoHashV2))),
|
||||||
|
new TorrentAction("copyMagnet", "Magnet link", Icons.Material.Filled.TextFields, Color.Info, CreateCallback(() => Copy(t => t.MagnetUri))),
|
||||||
|
new TorrentAction("copyId", "Torrent ID", Icons.Material.Filled.TextFields, Color.Info, CreateCallback(() => Copy(t => t.Hash))),
|
||||||
|
}),
|
||||||
|
new TorrentAction("export", "Export", Icons.Material.Filled.SaveAlt, Color.Info, CreateCallback(Export)),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
protected async Task Pause()
|
protected async Task Pause()
|
||||||
{
|
{
|
||||||
await ApiClient.PauseTorrents(Hashes);
|
await ApiClient.PauseTorrents(Hashes);
|
||||||
@@ -70,6 +113,12 @@ namespace Lantean.QBTMudBlade.Components
|
|||||||
Snackbar.Add("Torrent resumed.");
|
Snackbar.Add("Torrent resumed.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected async Task ForceStart()
|
||||||
|
{
|
||||||
|
await ApiClient.SetForceStart(true, null, Hashes.ToArray());
|
||||||
|
Snackbar.Add("Torrent force started.");
|
||||||
|
}
|
||||||
|
|
||||||
protected async Task Remove()
|
protected async Task Remove()
|
||||||
{
|
{
|
||||||
await DialogService.InvokeDeleteTorrentDialog(ApiClient, Hashes.ToArray());
|
await DialogService.InvokeDeleteTorrentDialog(ApiClient, Hashes.ToArray());
|
||||||
@@ -117,6 +166,18 @@ namespace Lantean.QBTMudBlade.Components
|
|||||||
await ApiClient.SetAutomaticTorrentManagement(true, null, torrents.Where(t => !t.AutomaticTorrentManagement).Select(t => t.Hash).ToArray());
|
await ApiClient.SetAutomaticTorrentManagement(true, null, torrents.Where(t => !t.AutomaticTorrentManagement).Select(t => t.Hash).ToArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected async Task LimitDownloadRate()
|
||||||
|
{
|
||||||
|
long downloadLimit = -1;
|
||||||
|
string hash = Hashes.First();
|
||||||
|
if (Hashes.Any() && MainData.Torrents.TryGetValue(hash, out var torrent))
|
||||||
|
{
|
||||||
|
downloadLimit = torrent.UploadLimit;
|
||||||
|
}
|
||||||
|
|
||||||
|
await DialogService.InvokeDownloadRateDialog(ApiClient, downloadLimit, Hashes);
|
||||||
|
}
|
||||||
|
|
||||||
protected async Task LimitUploadRate()
|
protected async Task LimitUploadRate()
|
||||||
{
|
{
|
||||||
long uploadLimit = -1;
|
long uploadLimit = -1;
|
||||||
@@ -220,6 +281,16 @@ namespace Lantean.QBTMudBlade.Components
|
|||||||
await DialogService.ShowAsync<ManageCategoriesDialog>("Manage Torrent Categories", parameters, DialogHelper.FormDialogOptions);
|
await DialogService.ShowAsync<ManageCategoriesDialog>("Manage Torrent Categories", parameters, DialogHelper.FormDialogOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected async Task DownloadSequential()
|
||||||
|
{
|
||||||
|
await ApiClient.ToggleSequentialDownload(null, Hashes.ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async Task DownloadFirstLast()
|
||||||
|
{
|
||||||
|
await ApiClient.SetFirstLastPiecePriority(null, Hashes.ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
protected async Task SubMenuTouch(TorrentAction action)
|
protected async Task SubMenuTouch(TorrentAction action)
|
||||||
{
|
{
|
||||||
await DialogService.ShowSubMenu(Hashes, action, MainData, Preferences);
|
await DialogService.ShowSubMenu(Hashes, action, MainData, Preferences);
|
||||||
@@ -236,71 +307,214 @@ namespace Lantean.QBTMudBlade.Components
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<TorrentAction>? _actions;
|
private IEnumerable<TorrentAction> Actions => GetActions();
|
||||||
|
|
||||||
private IEnumerable<TorrentAction> Actions
|
private IEnumerable<TorrentAction> GetActions()
|
||||||
{
|
{
|
||||||
get
|
var allAreSequentialDownload = true;
|
||||||
|
var thereAreSequentialDownload = false;
|
||||||
|
var allAreFirstLastPiecePrio = true;
|
||||||
|
var thereAreFirstLastPiecePrio = false;
|
||||||
|
var allAreDownloaded = true;
|
||||||
|
var allArePaused = true;
|
||||||
|
var thereArePaused = false;
|
||||||
|
var allAreForceStart = true;
|
||||||
|
var thereAreForceStart = false;
|
||||||
|
var allAreSuperSeeding = true;
|
||||||
|
var allAreAutoTmm = true;
|
||||||
|
var thereAreAutoTmm = false;
|
||||||
|
|
||||||
|
Torrent? firstTorrent = null;
|
||||||
|
foreach (var torrent in GetTorrents())
|
||||||
{
|
{
|
||||||
if (_actions is not null)
|
if (firstTorrent is null)
|
||||||
{
|
{
|
||||||
if (Preferences?.QueueingEnabled == false)
|
firstTorrent = torrent;
|
||||||
{
|
}
|
||||||
return _actions.Where(a => a.Name != "Queue");
|
if (!torrent.SequentialDownload)
|
||||||
}
|
{
|
||||||
return _actions;
|
allAreSequentialDownload = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
thereAreSequentialDownload = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Torrent? torrent = null;
|
if (!torrent.FirstLastPiecePriority)
|
||||||
if (Hashes.Any())
|
|
||||||
{
|
{
|
||||||
string key = Hashes.First();
|
allAreFirstLastPiecePrio = false;
|
||||||
if (!MainData.Torrents.TryGetValue(key, out torrent))
|
}
|
||||||
{
|
else
|
||||||
Hashes = Hashes.Except([key]);
|
{
|
||||||
}
|
thereAreFirstLastPiecePrio = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
_actions = new List<TorrentAction>
|
if (torrent.Progress != 1.0) // not downloaded
|
||||||
{
|
{
|
||||||
new TorrentAction("Pause", Icons.Material.Filled.Pause, Color.Warning, CreateCallback(Pause)),
|
allAreDownloaded = false;
|
||||||
new TorrentAction("Resume", Icons.Material.Filled.PlayArrow, Color.Success, CreateCallback(Resume)),
|
}
|
||||||
new Divider(),
|
else if (!torrent.SuperSeeding)
|
||||||
new TorrentAction("Remove", Icons.Material.Filled.Delete, Color.Error, CreateCallback(Remove)),
|
{
|
||||||
new Divider(),
|
allAreSuperSeeding = false;
|
||||||
new TorrentAction("Set location", Icons.Material.Filled.MyLocation, Color.Info, CreateCallback(SetLocation)),
|
}
|
||||||
new TorrentAction("Rename", Icons.Material.Filled.DriveFileRenameOutline, Color.Info, CreateCallback(Rename)),
|
|
||||||
new TorrentAction("Category", Icons.Material.Filled.List, Color.Info, CreateCallback(ShowCategories)),
|
|
||||||
new TorrentAction("Tags", Icons.Material.Filled.Label, Color.Info, CreateCallback(ShowTags)),
|
|
||||||
new TorrentAction("Automatic Torrent Management", Icons.Material.Filled.Check, (torrent?.AutomaticTorrentManagement == true) ? Color.Info : Color.Transparent, CreateCallback(ToggleAutoTMM)),
|
|
||||||
new Divider(),
|
|
||||||
new TorrentAction("Limit upload rate", Icons.Material.Filled.KeyboardDoubleArrowUp, Color.Info, CreateCallback(LimitUploadRate)),
|
|
||||||
new TorrentAction("Limit share ratio", Icons.Material.Filled.Percent, Color.Warning, CreateCallback(LimitShareRatio)),
|
|
||||||
new TorrentAction("Super seeding mode", Icons.Material.Filled.Check, (torrent?.SuperSeeding == true) ? Color.Info : Color.Transparent, CreateCallback(ToggleSuperSeeding)),
|
|
||||||
new Divider(),
|
|
||||||
new TorrentAction("Force recheck", Icons.Material.Filled.Loop, Color.Info, CreateCallback(ForceRecheck)),
|
|
||||||
new TorrentAction("Force reannounce", Icons.Material.Filled.BroadcastOnHome, Color.Info, CreateCallback(ForceReannounce)),
|
|
||||||
new Divider(),
|
|
||||||
new TorrentAction("Queue", Icons.Material.Filled.Queue, Color.Transparent, new List<TorrentAction>
|
|
||||||
{
|
|
||||||
new TorrentAction("Move to top", Icons.Material.Filled.VerticalAlignTop, Color.Inherit, CreateCallback(MoveToTop)),
|
|
||||||
new TorrentAction("Move up", Icons.Material.Filled.ArrowUpward, Color.Inherit, CreateCallback(MoveUp)),
|
|
||||||
new TorrentAction("Move down", Icons.Material.Filled.ArrowDownward, Color.Inherit, CreateCallback(MoveDown)),
|
|
||||||
new TorrentAction("Move to bottom", Icons.Material.Filled.VerticalAlignBottom, Color.Inherit, CreateCallback(MoveToBottom)),
|
|
||||||
}),
|
|
||||||
new TorrentAction("Copy", Icons.Material.Filled.FolderCopy, Color.Info, new List<TorrentAction>
|
|
||||||
{
|
|
||||||
new TorrentAction("Name", Icons.Material.Filled.TextFields, Color.Info, CreateCallback(() => Copy(t => t.Name))),
|
|
||||||
new TorrentAction("Info hash v1", Icons.Material.Filled.Tag, Color.Info, CreateCallback(() => Copy(t => t.InfoHashV1))),
|
|
||||||
new TorrentAction("Info hash v2", Icons.Material.Filled.Tag, Color.Info, CreateCallback(() => Copy(t => t.InfoHashV2))),
|
|
||||||
new TorrentAction("Magnet link", Icons.Material.Filled.TextFields, Color.Info, CreateCallback(() => Copy(t => t.MagnetUri))),
|
|
||||||
new TorrentAction("Torrent ID", Icons.Material.Filled.TextFields, Color.Info, CreateCallback(() => Copy(t => t.Hash))),
|
|
||||||
}),
|
|
||||||
new TorrentAction("Export", Icons.Material.Filled.SaveAlt, Color.Info, CreateCallback(Export)),
|
|
||||||
};
|
|
||||||
|
|
||||||
return _actions;
|
if (torrent.State != "pausedUP" && torrent.State != "pausedDL")
|
||||||
|
{
|
||||||
|
allArePaused = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
thereArePaused = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!torrent.ForceStart)
|
||||||
|
{
|
||||||
|
allAreForceStart = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
thereAreForceStart = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (torrent.AutomaticTorrentManagement)
|
||||||
|
{
|
||||||
|
thereAreAutoTmm = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
allAreAutoTmm = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool showSequentialDownload = true;
|
||||||
|
if (!allAreSequentialDownload && thereAreSequentialDownload)
|
||||||
|
{
|
||||||
|
showSequentialDownload = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool showAreFirstLastPiecePrio = true;
|
||||||
|
if (!allAreFirstLastPiecePrio && thereAreFirstLastPiecePrio)
|
||||||
|
{
|
||||||
|
showAreFirstLastPiecePrio = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var actionStates = new Dictionary<string, ActionState>();
|
||||||
|
|
||||||
|
var showRenameFiles = Hashes.Count() == 1 && firstTorrent!.MetaDownloaded();
|
||||||
|
if (!showRenameFiles)
|
||||||
|
{
|
||||||
|
actionStates["renameFiles"] = ActionState.Hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (allAreDownloaded)
|
||||||
|
{
|
||||||
|
actionStates["downloadLimit"] = ActionState.Hidden;
|
||||||
|
actionStates["uploadLimit"] = ActionState.HasSeperator;
|
||||||
|
actionStates["sequentialDownload"] = ActionState.Hidden;
|
||||||
|
actionStates["firstLastPiecePrio"] = ActionState.Hidden;
|
||||||
|
actionStates["superSeeding"] = new ActionState { IsChecked = allAreSuperSeeding };
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!showSequentialDownload && showAreFirstLastPiecePrio)
|
||||||
|
{
|
||||||
|
actionStates["firstLastPiecePrio"] = ActionState.HasSeperator;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!showSequentialDownload)
|
||||||
|
{
|
||||||
|
actionStates["sequentialDownload"] = ActionState.Hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!showAreFirstLastPiecePrio)
|
||||||
|
{
|
||||||
|
actionStates["firstLastPiecePrio"] = ActionState.Hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!actionStates.TryGetValue("sequentialDownload", out var sequentialDownload))
|
||||||
|
{
|
||||||
|
actionStates["sequentialDownload"] = new ActionState { IsChecked = allAreSequentialDownload };
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sequentialDownload.IsChecked = allAreSequentialDownload;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!actionStates.TryGetValue("firstLastPiecePrio", out var firstLastPiecePrio))
|
||||||
|
{
|
||||||
|
actionStates["firstLastPiecePrio"] = new ActionState { IsChecked = allAreFirstLastPiecePrio };
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
firstLastPiecePrio.IsChecked = allAreFirstLastPiecePrio;
|
||||||
|
}
|
||||||
|
|
||||||
|
actionStates["superSeeding"] = ActionState.Hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (allArePaused)
|
||||||
|
{
|
||||||
|
actionStates["pause"] = ActionState.Hidden;
|
||||||
|
}
|
||||||
|
else if (allAreForceStart)
|
||||||
|
{
|
||||||
|
actionStates["forceStart"] = ActionState.Hidden;
|
||||||
|
}
|
||||||
|
else if (!thereArePaused && !thereAreForceStart)
|
||||||
|
{
|
||||||
|
actionStates["start"] = ActionState.Hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!allAreAutoTmm && thereAreAutoTmm)
|
||||||
|
{
|
||||||
|
actionStates["autoTorrentManagement"] = ActionState.Hidden;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
actionStates["autoTorrentManagement"] = new ActionState { IsChecked = allAreAutoTmm };
|
||||||
|
}
|
||||||
|
|
||||||
|
return Filter(actionStates);
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerable<TorrentAction> Filter(Dictionary<string, ActionState> actionStates)
|
||||||
|
{
|
||||||
|
foreach (var action in _actions)
|
||||||
|
{
|
||||||
|
if (!actionStates.TryGetValue(action.Name, out var actionState))
|
||||||
|
{
|
||||||
|
yield return action;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
if (actionState.Show is null || actionState.Show.Value)
|
||||||
|
{
|
||||||
|
var act = action with { };
|
||||||
|
if (actionState.HasSeparator.HasValue)
|
||||||
|
{
|
||||||
|
act.SeparatorBefore = actionState.HasSeparator.Value;
|
||||||
|
}
|
||||||
|
if (actionState.IsChecked.HasValue)
|
||||||
|
{
|
||||||
|
act.IsChecked = actionState.IsChecked.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private sealed class ActionState
|
||||||
|
{
|
||||||
|
public bool? Show { get; set; }
|
||||||
|
|
||||||
|
public bool? HasSeparator { get; set; }
|
||||||
|
|
||||||
|
public bool? IsChecked { get; set; }
|
||||||
|
|
||||||
|
public static readonly ActionState Hidden = new ActionState { Show = false };
|
||||||
|
|
||||||
|
public static readonly ActionState HasSeperator = new ActionState { HasSeparator = true };
|
||||||
}
|
}
|
||||||
|
|
||||||
private EventCallback CreateCallback(Func<Task> action, bool ignoreAfterAction = false)
|
private EventCallback CreateCallback(Func<Task> action, bool ignoreAfterAction = false)
|
||||||
@@ -351,46 +565,53 @@ namespace Lantean.QBTMudBlade.Components
|
|||||||
Children,
|
Children,
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Divider : TorrentAction
|
public record TorrentAction
|
||||||
{
|
{
|
||||||
public Divider() : base("-", default!, Color.Default, default(EventCallback))
|
private readonly Color _color;
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class TorrentAction
|
public TorrentAction(string name, string text, string? icon, Color color, EventCallback callback, bool separatorBefore = false)
|
||||||
{
|
|
||||||
public TorrentAction(string name, string? icon, Color color, EventCallback callback)
|
|
||||||
{
|
{
|
||||||
Name = name;
|
Name = name;
|
||||||
|
Text = text;
|
||||||
Icon = icon;
|
Icon = icon;
|
||||||
Color = color;
|
_color = color;
|
||||||
Callback = callback;
|
Callback = callback;
|
||||||
|
SeparatorBefore = separatorBefore;
|
||||||
Children = [];
|
Children = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
public TorrentAction(string name, string? icon, Color color, IEnumerable<TorrentAction> children, bool multiAction = false, bool useTextButton = false)
|
public TorrentAction(string name, string text, string? icon, Color color, IEnumerable<TorrentAction> children, bool multiAction = false, bool useTextButton = false, bool separatorBefore = false)
|
||||||
{
|
{
|
||||||
Name = name;
|
Name = name;
|
||||||
|
Text = text;
|
||||||
Icon = icon;
|
Icon = icon;
|
||||||
Color = color;
|
_color = color;
|
||||||
Callback = default;
|
Callback = default;
|
||||||
Children = children;
|
Children = children;
|
||||||
UseTextButton = useTextButton;
|
UseTextButton = useTextButton;
|
||||||
|
SeparatorBefore = separatorBefore;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Name { get; }
|
public string Name { get; }
|
||||||
|
|
||||||
|
public string Text { get; }
|
||||||
|
|
||||||
public string? Icon { get; }
|
public string? Icon { get; }
|
||||||
|
|
||||||
public Color Color { get; }
|
|
||||||
|
|
||||||
|
public Color Color => IsChecked is null || IsChecked.Value ? _color : Color.Transparent;
|
||||||
|
|
||||||
public EventCallback Callback { get; }
|
public EventCallback Callback { get; }
|
||||||
|
|
||||||
|
public bool SeparatorBefore { get; set; }
|
||||||
|
|
||||||
public IEnumerable<TorrentAction> Children { get; }
|
public IEnumerable<TorrentAction> Children { get; }
|
||||||
|
|
||||||
public bool UseTextButton { get; }
|
public bool UseTextButton { get; }
|
||||||
|
|
||||||
public bool MultiAction { get; }
|
public bool MultiAction { get; }
|
||||||
|
|
||||||
|
public bool? IsChecked { get; internal set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -194,6 +194,25 @@ namespace Lantean.QBTMudBlade
|
|||||||
await onSuccess((T)dialogResult.Data);
|
await onSuccess((T)dialogResult.Data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static async Task InvokeDownloadRateDialog(this IDialogService dialogService, IApiClient apiClient, long rate, IEnumerable<string> hashes)
|
||||||
|
{
|
||||||
|
var parameters = new DialogParameters
|
||||||
|
{
|
||||||
|
{ nameof(SliderFieldDialog<long>.Value), rate },
|
||||||
|
{ nameof(SliderFieldDialog<long>.Min), 0L },
|
||||||
|
{ nameof(SliderFieldDialog<long>.Max), 100L },
|
||||||
|
};
|
||||||
|
var result = await dialogService.ShowAsync<SliderFieldDialog<long>>("Download Rate", parameters, FormDialogOptions);
|
||||||
|
|
||||||
|
var dialogResult = await result.Result;
|
||||||
|
if (dialogResult.Canceled)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await apiClient.SetTorrentDownloadLimit((long)dialogResult.Data, null, hashes.ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
public static async Task InvokeUploadRateDialog(this IDialogService dialogService, IApiClient apiClient, long rate, IEnumerable<string> hashes)
|
public static async Task InvokeUploadRateDialog(this IDialogService dialogService, IApiClient apiClient, long rate, IEnumerable<string> hashes)
|
||||||
{
|
{
|
||||||
var parameters = new DialogParameters
|
var parameters = new DialogParameters
|
||||||
@@ -282,7 +301,7 @@ namespace Lantean.QBTMudBlade
|
|||||||
{ nameof(SubMenuDialog.Preferences), preferences },
|
{ nameof(SubMenuDialog.Preferences), preferences },
|
||||||
};
|
};
|
||||||
|
|
||||||
await dialogService.ShowAsync<SubMenuDialog>(parent.Name, parameters, FormDialogOptions);
|
await dialogService.ShowAsync<SubMenuDialog>(parent.Text, parameters, FormDialogOptions);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -49,5 +49,15 @@ namespace Lantean.QBTMudBlade
|
|||||||
// disposed
|
// disposed
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool IsFinished(this Torrent torrent)
|
||||||
|
{
|
||||||
|
return torrent.TotalSize == torrent.Downloaded;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool MetaDownloaded(this Torrent torrent)
|
||||||
|
{
|
||||||
|
return !(torrent.State == "metaDL" || torrent.State == "forcedMetaDL" || torrent.TotalSize == -1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -45,7 +45,7 @@ namespace Lantean.QBTMudBlade.Models
|
|||||||
|
|
||||||
public long Downloaded => (long)Math.Round(Size * Progress, 0);
|
public long Downloaded => (long)Math.Round(Size * Progress, 0);
|
||||||
|
|
||||||
public long Remaining => Progress == 1 ? 0 : Size - Downloaded;
|
public long Remaining => Progress == 1 || Priority == Priority.DoNotDownload ? 0 : Size - Downloaded;
|
||||||
|
|
||||||
public bool IsFolder { get; }
|
public bool IsFolder { get; }
|
||||||
|
|
||||||
|
|||||||
@@ -47,12 +47,10 @@ namespace Lantean.QBTMudBlade.Pages
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
await DoLogin("admin", "23mIDZhvT");
|
await DoLogin("admin", "MX6r8xzTP");
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
9
Lantean.QBTMudBlade/readme.md
Normal file
9
Lantean.QBTMudBlade/readme.md
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# qbt-mud
|
||||||
|
|
||||||
|
## To-Do
|
||||||
|
|
||||||
|
- Files -> Context menu alternative
|
||||||
|
- Details -> Fixed height
|
||||||
|
- Rename multiple files dialog
|
||||||
|
- RSS feeds and dialogs
|
||||||
|
- Search and dialogs
|
||||||
Reference in New Issue
Block a user