Added select folder dialog. Added item moving as a module
This commit is contained in:
@@ -53,9 +53,11 @@ public class FileManagerFeature : MoonlightFeature
|
|||||||
var pluginService = context.Application.Services.GetRequiredService<PluginService>();
|
var pluginService = context.Application.Services.GetRequiredService<PluginService>();
|
||||||
|
|
||||||
await pluginService.RegisterImplementation<IFileManagerContextAction>(new RenameContextAction());
|
await pluginService.RegisterImplementation<IFileManagerContextAction>(new RenameContextAction());
|
||||||
|
await pluginService.RegisterImplementation<IFileManagerContextAction>(new MoveContextAction());
|
||||||
await pluginService.RegisterImplementation<IFileManagerContextAction>(new DownloadContextAction());
|
await pluginService.RegisterImplementation<IFileManagerContextAction>(new DownloadContextAction());
|
||||||
await pluginService.RegisterImplementation<IFileManagerContextAction>(new DeleteContextAction());
|
await pluginService.RegisterImplementation<IFileManagerContextAction>(new DeleteContextAction());
|
||||||
|
|
||||||
|
await pluginService.RegisterImplementation<IFileManagerSelectionAction>(new MoveSelectionAction());
|
||||||
await pluginService.RegisterImplementation<IFileManagerSelectionAction>(new DeleteSelectionAction());
|
await pluginService.RegisterImplementation<IFileManagerSelectionAction>(new DeleteSelectionAction());
|
||||||
|
|
||||||
await pluginService.RegisterImplementation<IFileManagerCreateAction>(new CreateFileAction());
|
await pluginService.RegisterImplementation<IFileManagerCreateAction>(new CreateFileAction());
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ public class DeleteSelectionAction : IFileManagerSelectionAction
|
|||||||
|
|
||||||
await toastService.RemoveProgress("fileManagerSelectionDelete");
|
await toastService.RemoveProgress("fileManagerSelectionDelete");
|
||||||
|
|
||||||
await toastService.Success($"Successfully deleted selection");
|
await toastService.Success("Successfully deleted selection");
|
||||||
|
await fileManager.View.Refresh();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
using MoonCoreUI.Services;
|
||||||
|
using Moonlight.Features.FileManager.Interfaces;
|
||||||
|
using Moonlight.Features.FileManager.Models.Abstractions.FileAccess;
|
||||||
|
|
||||||
|
namespace Moonlight.Features.FileManager.Implementations;
|
||||||
|
|
||||||
|
public class MoveContextAction : IFileManagerContextAction
|
||||||
|
{
|
||||||
|
public string Name => "Move";
|
||||||
|
public string Icon => "bx-move";
|
||||||
|
public string Color => "info";
|
||||||
|
public Func<FileEntry, bool> Filter => _ => true;
|
||||||
|
|
||||||
|
public async Task Execute(BaseFileAccess access, UI.NewFileManager.FileManager fileManager, FileEntry entry, IServiceProvider provider)
|
||||||
|
{
|
||||||
|
await fileManager.OpenFolderSelect("Select the location to move the item to", async path =>
|
||||||
|
{
|
||||||
|
var toastService = provider.GetRequiredService<ToastService>();
|
||||||
|
|
||||||
|
await access.Move(entry, path + entry.Name);
|
||||||
|
|
||||||
|
await toastService.Success("Successfully moved item");
|
||||||
|
await fileManager.View.Refresh();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
using MoonCoreUI.Services;
|
||||||
|
using Moonlight.Features.FileManager.Interfaces;
|
||||||
|
using Moonlight.Features.FileManager.Models.Abstractions.FileAccess;
|
||||||
|
|
||||||
|
namespace Moonlight.Features.FileManager.Implementations;
|
||||||
|
|
||||||
|
public class MoveSelectionAction : IFileManagerSelectionAction
|
||||||
|
{
|
||||||
|
public string Name => "Move";
|
||||||
|
public string Color => "primary";
|
||||||
|
|
||||||
|
public async Task Execute(BaseFileAccess access, UI.NewFileManager.FileManager fileManager, FileEntry[] entries, IServiceProvider provider)
|
||||||
|
{
|
||||||
|
await fileManager.OpenFolderSelect("Select the location to move the items to", async path =>
|
||||||
|
{
|
||||||
|
var toastService = provider.GetRequiredService<ToastService>();
|
||||||
|
|
||||||
|
await toastService.CreateProgress("fileManagerSelectionMove", "Moving items");
|
||||||
|
|
||||||
|
foreach (var entry in entries)
|
||||||
|
{
|
||||||
|
await toastService.ModifyProgress("fileManagerSelectionMove", $"Moving '{entry.Name}'");
|
||||||
|
|
||||||
|
await access.Move(entry, path + entry.Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
await toastService.RemoveProgress("fileManagerSelectionMove");
|
||||||
|
|
||||||
|
await toastService.Success("Successfully moved selection");
|
||||||
|
await fileManager.View.Refresh();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -50,8 +50,8 @@
|
|||||||
foreach (var action in SelectionActions)
|
foreach (var action in SelectionActions)
|
||||||
{
|
{
|
||||||
var cssClass = $"btn btn-{action.Color} mx-2";
|
var cssClass = $"btn btn-{action.Color} mx-2";
|
||||||
|
|
||||||
<WButton Text="@action.Name" CssClasses="@cssClass" OnClick="() => InvokeSelectionAction(action)" />
|
<WButton Text="@action.Name" CssClasses="@cssClass" OnClick="() => InvokeSelectionAction(action)"/>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -100,42 +100,37 @@ else
|
|||||||
<ContextMenuTemplate>
|
<ContextMenuTemplate>
|
||||||
@foreach (var action in ContextActions)
|
@foreach (var action in ContextActions)
|
||||||
{
|
{
|
||||||
if(!action.Filter.Invoke(context))
|
if (!action.Filter.Invoke(context))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
<a class="dropdown-item" href="#" @onclick:preventDefault @onclick="() => InvokeContextAction(action, context)">
|
<a class="dropdown-item" href="#" @onclick:preventDefault @onclick="() => InvokeContextAction(action, context)">
|
||||||
<i class="bx bx-sm @action.Icon text-@action.Color align-middle"></i>
|
<i class="bx bx-sm @action.Icon text-@action.Color align-middle"></i>
|
||||||
<span class="align-middle ms-3">@action.Name</span>
|
<span class="align-middle ms-3">@action.Name</span>
|
||||||
</a>
|
</a>
|
||||||
}
|
}
|
||||||
|
|
||||||
<a class="dropdown-item" href="#" @onclick:preventDefault @onclick="() => Move(context)">
|
|
||||||
<i class="bx bx-sm bx-move text-info align-middle"></i>
|
|
||||||
<span class="align-middle ms-3">Move</span>
|
|
||||||
</a>
|
|
||||||
</ContextMenuTemplate>
|
</ContextMenuTemplate>
|
||||||
</FileView>
|
</FileView>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<SmartModal @ref="MoveModal" CssClasses="modal-lg modal-dialog-centered">
|
<SmartModal @ref="FolderSelectModal" CssClasses="modal-lg modal-dialog-centered">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<h5 class="modal-title">Select a new location</h5>
|
<h5 class="modal-title">@FolderSelectTitle</h5>
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close" @onclick="HideMove"></button>
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close" @onclick="HideFolderSelect"></button>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<FileView @ref="MoveView"
|
<FileView @ref="FolderSelectView"
|
||||||
FileAccess="MoveAccess"
|
FileAccess="FolderSelectFileAccess"
|
||||||
Filter="FolderOnlyFilter"
|
Filter="FolderSelectFilter"
|
||||||
ShowDate="false"
|
ShowDate="false"
|
||||||
ShowSelect="false"
|
ShowSelect="false"
|
||||||
ShowSize="false"
|
ShowSize="false"
|
||||||
OnEntryClicked="OnFolderClicked"
|
OnEntryClicked="EntryClickFolderSelect"
|
||||||
OnNavigateUpClicked="OnMoveUpClicked"
|
OnNavigateUpClicked="NavigateUpFolderSelect"
|
||||||
EnableContextMenu="false"/>
|
EnableContextMenu="false"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal" @onclick="HideMove">Close</button>
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal" @onclick="HideFolderSelect">Cancel</button>
|
||||||
<button type="button" class="btn btn-primary" @onclick="FinishMove">Save changes</button>
|
<button type="button" class="btn btn-primary" @onclick="SubmitFolderSelect">Submit</button>
|
||||||
</div>
|
</div>
|
||||||
</SmartModal>
|
</SmartModal>
|
||||||
}
|
}
|
||||||
@@ -156,15 +151,14 @@ else
|
|||||||
private FileEntry FileToEdit;
|
private FileEntry FileToEdit;
|
||||||
private bool ShowEditor = false;
|
private bool ShowEditor = false;
|
||||||
|
|
||||||
// Move
|
// Folder select dialog
|
||||||
private SmartModal MoveModal;
|
private bool FolderSelectIsOpen = false;
|
||||||
private BaseFileAccess MoveAccess;
|
private SmartModal FolderSelectModal;
|
||||||
private FileView MoveView;
|
private BaseFileAccess FolderSelectFileAccess;
|
||||||
private bool InMoveState = false;
|
private string FolderSelectTitle;
|
||||||
private Func<FileEntry, bool> FolderOnlyFilter = entry => entry.IsDirectory;
|
private Func<string, Task> FolderSelectResult;
|
||||||
private Func<FileEntry, Task> OnFolderClicked;
|
private FileView FolderSelectView;
|
||||||
private Func<Task> OnMoveUpClicked;
|
private Func<FileEntry, bool> FolderSelectFilter => entry => entry.IsDirectory;
|
||||||
private List<FileEntry> FilesToMove = new();
|
|
||||||
|
|
||||||
private Timer? UploadTokenTimer;
|
private Timer? UploadTokenTimer;
|
||||||
|
|
||||||
@@ -174,17 +168,6 @@ else
|
|||||||
ContextActions = await PluginService.GetImplementations<IFileManagerContextAction>();
|
ContextActions = await PluginService.GetImplementations<IFileManagerContextAction>();
|
||||||
SelectionActions = await PluginService.GetImplementations<IFileManagerSelectionAction>();
|
SelectionActions = await PluginService.GetImplementations<IFileManagerSelectionAction>();
|
||||||
CreateActions = await PluginService.GetImplementations<IFileManagerCreateAction>();
|
CreateActions = await PluginService.GetImplementations<IFileManagerCreateAction>();
|
||||||
|
|
||||||
OnFolderClicked = async entry =>
|
|
||||||
{
|
|
||||||
await MoveAccess.ChangeDirectory(entry.Name);
|
|
||||||
await MoveView.Refresh();
|
|
||||||
};
|
|
||||||
OnMoveUpClicked = async () =>
|
|
||||||
{
|
|
||||||
await MoveAccess.ChangeDirectory("..");
|
|
||||||
await MoveView.Refresh();
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||||
@@ -250,7 +233,7 @@ else
|
|||||||
private async Task InvokeSelectionAction(IFileManagerSelectionAction action)
|
private async Task InvokeSelectionAction(IFileManagerSelectionAction action)
|
||||||
{
|
{
|
||||||
await action.Execute(FileAccess, this, View.Selection, ServiceProvider);
|
await action.Execute(FileAccess, this, View.Selection, ServiceProvider);
|
||||||
|
|
||||||
// Refresh resets the selection
|
// Refresh resets the selection
|
||||||
await View.Refresh();
|
await View.Refresh();
|
||||||
}
|
}
|
||||||
@@ -259,7 +242,7 @@ else
|
|||||||
{
|
{
|
||||||
await action.Execute(FileAccess, this, ServiceProvider);
|
await action.Execute(FileAccess, this, ServiceProvider);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task OnSelectionChanged(FileEntry[] _) => await InvokeAsync(StateHasChanged);
|
private async Task OnSelectionChanged(FileEntry[] _) => await InvokeAsync(StateHasChanged);
|
||||||
|
|
||||||
#region Navigation & Refreshing
|
#region Navigation & Refreshing
|
||||||
@@ -306,7 +289,7 @@ else
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region File Editor
|
#region File Editor
|
||||||
|
|
||||||
public async Task OpenEditor(FileEntry entry)
|
public async Task OpenEditor(FileEntry entry)
|
||||||
@@ -325,75 +308,48 @@ else
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Move
|
#region Selects
|
||||||
|
|
||||||
private async Task Move(FileEntry entry)
|
public async Task OpenFolderSelect(string title, Func<string, Task> onResult)
|
||||||
{
|
{
|
||||||
await View.HideContextMenu();
|
if (FolderSelectIsOpen)
|
||||||
|
await HideFolderSelect();
|
||||||
|
|
||||||
FilesToMove.Clear();
|
FolderSelectResult = onResult;
|
||||||
|
FolderSelectTitle = title;
|
||||||
|
|
||||||
FilesToMove.Add(entry);
|
FolderSelectFileAccess = FileAccess.Clone();
|
||||||
|
await FolderSelectFileAccess.SetDirectory("/");
|
||||||
|
|
||||||
await StartMove();
|
await FolderSelectModal.Show();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task MoveSelection()
|
public async Task HideFolderSelect()
|
||||||
{
|
{
|
||||||
FilesToMove.Clear();
|
await FolderSelectModal.Hide();
|
||||||
|
FolderSelectIsOpen = false;
|
||||||
FilesToMove.AddRange(View.Selection);
|
FolderSelectFileAccess.Dispose();
|
||||||
|
|
||||||
await StartMove();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task StartMove()
|
private async Task SubmitFolderSelect()
|
||||||
{
|
{
|
||||||
// Cleanup if modal was removed in any other way
|
var path = await FolderSelectFileAccess.GetCurrentDirectory();
|
||||||
if (InMoveState)
|
|
||||||
await HideMove();
|
|
||||||
|
|
||||||
// Prepare file access and show modal
|
await HideFolderSelect();
|
||||||
InMoveState = true;
|
|
||||||
await InvokeAsync(StateHasChanged);
|
|
||||||
|
|
||||||
MoveAccess = FileAccess.Clone();
|
await FolderSelectResult.Invoke(path);
|
||||||
await MoveAccess.SetDirectory("/");
|
|
||||||
|
|
||||||
await MoveModal.Show();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task HideMove()
|
private async Task NavigateUpFolderSelect()
|
||||||
{
|
{
|
||||||
await MoveModal.Hide();
|
await FolderSelectFileAccess.ChangeDirectory("..");
|
||||||
MoveAccess.Dispose();
|
await FolderSelectView.Refresh();
|
||||||
|
|
||||||
InMoveState = false;
|
|
||||||
await InvokeAsync(StateHasChanged);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task FinishMove()
|
private async Task EntryClickFolderSelect(FileEntry entry)
|
||||||
{
|
{
|
||||||
var target = await MoveAccess.GetCurrentDirectory();
|
await FolderSelectFileAccess.ChangeDirectory(entry.Name);
|
||||||
|
await FolderSelectView.Refresh();
|
||||||
await HideMove();
|
|
||||||
|
|
||||||
await ToastService.CreateProgress("fileManagerMoveFile", "Moving items");
|
|
||||||
|
|
||||||
var i = 1;
|
|
||||||
foreach (var entry in FilesToMove)
|
|
||||||
{
|
|
||||||
await ToastService.ModifyProgress("fileManagerMoveFile", $"[{i}/{FilesToMove.Count}] Moving items");
|
|
||||||
await FileAccess.Move(entry, target + entry.Name);
|
|
||||||
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
await ToastService.RemoveProgress("fileManagerMoveFile");
|
|
||||||
|
|
||||||
await ToastService.Success($"Successfully moved {FilesToMove.Count} items");
|
|
||||||
|
|
||||||
await View.Refresh();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|||||||
Reference in New Issue
Block a user