329 lines
11 KiB
Plaintext
329 lines
11 KiB
Plaintext
@using Moonlight.App.Helpers.Files
|
|
@using Moonlight.App.Helpers
|
|
@using Logging.Net
|
|
@using Moonlight.App.Services
|
|
@using Moonlight.App.Services.Interop
|
|
@using BlazorDownloadFile
|
|
|
|
@inject ToastService ToastService
|
|
@inject NavigationManager NavigationManager
|
|
@inject AlertService AlertService
|
|
@inject SmartTranslateService SmartTranslateService
|
|
@inject IBlazorDownloadFileService FileService
|
|
|
|
@if (Editing)
|
|
{
|
|
<FileEditor @ref="Editor"
|
|
InitialData="@EditorInitialData"
|
|
Language="@EditorLanguage"
|
|
OnCancel="() => Cancel()"
|
|
OnSubmit="(_) => Cancel(true)"
|
|
HideControls="false">
|
|
</FileEditor>
|
|
}
|
|
else
|
|
{
|
|
<div class="card mb-7">
|
|
<div class="card-header border-0 my-2">
|
|
<div class="card-title">
|
|
<div class="d-flex flex-stack">
|
|
<FilePath Access="Access" OnPathChanged="OnComponentStateChanged" />
|
|
</div>
|
|
</div>
|
|
<div class="card-toolbar">
|
|
<div class="d-flex justify-content-end align-items-center">
|
|
@if (View != null && View.SelectedFiles.Any())
|
|
{
|
|
<div class="fw-bold me-5">
|
|
<span class="me-2">@(View.SelectedFiles.Length) <TL>selected</TL></span>
|
|
</div>
|
|
|
|
<WButton Text="@(SmartTranslateService.Translate("Move"))"
|
|
WorkingText="@(SmartTranslateService.Translate("Moving"))"
|
|
CssClasses="btn-primary me-3"
|
|
OnClick="StartMoveFiles">
|
|
</WButton>
|
|
|
|
<WButton Text="@(SmartTranslateService.Translate("Compress"))"
|
|
WorkingText="@(SmartTranslateService.Translate("Compressing"))"
|
|
CssClasses="btn-primary me-3"
|
|
OnClick="CompressMultiple">
|
|
</WButton>
|
|
|
|
<WButton Text="@(SmartTranslateService.Translate("Delete"))"
|
|
WorkingText="@(SmartTranslateService.Translate("Deleting"))"
|
|
CssClasses="btn-danger"
|
|
OnClick="DeleteMultiple">
|
|
</WButton>
|
|
}
|
|
else
|
|
{
|
|
<button type="button" @onclick="Launch" class="btn btn-light-primary me-3">
|
|
<span class="svg-icon svg-icon-muted svg-icon-2">
|
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
<path opacity="0.3" d="M5 16C3.3 16 2 14.7 2 13C2 11.3 3.3 10 5 10H5.1C5 9.7 5 9.3 5 9C5 6.2 7.2 4 10 4C11.9 4 13.5 5 14.3 6.5C14.8 6.2 15.4 6 16 6C17.7 6 19 7.3 19 9C19 9.4 18.9 9.7 18.8 10C18.9 10 18.9 10 19 10C20.7 10 22 11.3 22 13C22 14.7 20.7 16 19 16H5ZM8 13.6H16L12.7 10.3C12.3 9.89999 11.7 9.89999 11.3 10.3L8 13.6Z" fill="currentColor"/>
|
|
<path d="M11 13.6V19C11 19.6 11.4 20 12 20C12.6 20 13 19.6 13 19V13.6H11Z" fill="currentColor"/>
|
|
</svg>
|
|
</span>
|
|
<TL>Launch WinSCP</TL>
|
|
</button>
|
|
|
|
<button type="button" @onclick="CreateFolder" class="btn btn-light-primary me-3">
|
|
<span class="svg-icon svg-icon-2">
|
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
<path opacity="0.3" d="M10 4H21C21.6 4 22 4.4 22 5V7H10V4Z" fill="currentColor"></path>
|
|
<path d="M10.4 3.60001L12 6H21C21.6 6 22 6.4 22 7V19C22 19.6 21.6 20 21 20H3C2.4 20 2 19.6 2 19V4C2 3.4 2.4 3 3 3H9.2C9.7 3 10.2 3.20001 10.4 3.60001ZM16 12H13V9C13 8.4 12.6 8 12 8C11.4 8 11 8.4 11 9V12H8C7.4 12 7 12.4 7 13C7 13.6 7.4 14 8 14H11V17C11 17.6 11.4 18 12 18C12.6 18 13 17.6 13 17V14H16C16.6 14 17 13.6 17 13C17 12.4 16.6 12 16 12Z" fill="currentColor"></path>
|
|
<path opacity="0.3" d="M11 14H8C7.4 14 7 13.6 7 13C7 12.4 7.4 12 8 12H11V14ZM16 12H13V14H16C16.6 14 17 13.6 17 13C17 12.4 16.6 12 16 12Z" fill="currentColor"></path>
|
|
</svg>
|
|
</span>
|
|
<TL>New folder</TL>
|
|
</button>
|
|
|
|
<FileUpload Access="Access" OnUploadComplete="OnComponentStateChanged" />
|
|
}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card card-body ps-9">
|
|
<FileView @ref="View"
|
|
Access="Access"
|
|
ContextActions="Actions"
|
|
OnSelectionChanged="OnSelectionChanged"
|
|
OnElementClicked="OnElementClicked"
|
|
DisableScrolling="true">
|
|
</FileView>
|
|
</div>
|
|
|
|
<FileSelectModal @ref="FileSelectModal"
|
|
OnlyFolder="true"
|
|
Title="@(SmartTranslateService.Translate("Select folder to move the file(s) to"))"
|
|
Access="MoveAccess"
|
|
OnSubmit="OnFileMoveSubmit">
|
|
</FileSelectModal>
|
|
}
|
|
|
|
@code
|
|
{
|
|
[Parameter]
|
|
public FileAccess Access { get; set; }
|
|
|
|
// File Editor
|
|
private bool Editing = false;
|
|
private string EditorInitialData = "";
|
|
private string EditorLanguage = "";
|
|
private FileData EditingFile;
|
|
private FileEditor Editor;
|
|
|
|
// File View
|
|
private FileView? View;
|
|
|
|
// File Move
|
|
private FileAccess MoveAccess;
|
|
private FileSelectModal FileSelectModal;
|
|
private FileData? SingleMoveFile = null;
|
|
|
|
// Config
|
|
private ContextAction[] Actions = Array.Empty<ContextAction>();
|
|
|
|
protected override void OnInitialized()
|
|
{
|
|
MoveAccess = (FileAccess)Access.Clone();
|
|
|
|
List<ContextAction> actions = new();
|
|
|
|
actions.Add(new()
|
|
{
|
|
Id = "rename",
|
|
Name = "Rename",
|
|
Action = async (x) =>
|
|
{
|
|
var name = await AlertService.Text(
|
|
SmartTranslateService.Translate("Rename"),
|
|
SmartTranslateService.Translate("Enter a new name"),
|
|
x.Name
|
|
);
|
|
|
|
if (name != x.Name)
|
|
{
|
|
await Access.Move(x, Access.CurrentPath + name);
|
|
}
|
|
|
|
await View!.Refresh();
|
|
}
|
|
});
|
|
|
|
actions.Add(new ()
|
|
{
|
|
Id = "download",
|
|
Name = "Download",
|
|
Action = async (x) =>
|
|
{
|
|
if (x.IsFile)
|
|
{
|
|
try
|
|
{
|
|
var stream = await Access.DownloadStream(x);
|
|
await ToastService.Info(SmartTranslateService.Translate("Starting download"));
|
|
stream.Position = 0;
|
|
await FileService.DownloadFile(fileName: x.Name, stream: stream, contentType: "application/octet-stream");
|
|
}
|
|
catch (NotImplementedException)
|
|
{
|
|
var url = await Access.DownloadUrl(x);
|
|
NavigationManager.NavigateTo(url, true);
|
|
await ToastService.Info(SmartTranslateService.Translate("Starting download"));
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
actions.Add(new()
|
|
{
|
|
Id = "compress",
|
|
Name = "Compress",
|
|
Action = async (x) =>
|
|
{
|
|
await Access.Compress(x);
|
|
await View!.Refresh();
|
|
}
|
|
});
|
|
|
|
actions.Add(new ()
|
|
{
|
|
Id = "decompress",
|
|
Name = "Decompress",
|
|
Action = async (x) =>
|
|
{
|
|
await Access.Decompress(x);
|
|
await View!.Refresh();
|
|
}
|
|
});
|
|
|
|
actions.Add(new()
|
|
{
|
|
Id = "move",
|
|
Name = "Move",
|
|
Action = async (x) =>
|
|
{
|
|
SingleMoveFile = x;
|
|
await StartMoveFiles();
|
|
}
|
|
});
|
|
|
|
actions.Add(new()
|
|
{
|
|
Id = "delete",
|
|
Name = "Delete",
|
|
Action = async (x) =>
|
|
{
|
|
await Access.Delete(x);
|
|
await View!.Refresh();
|
|
}
|
|
});
|
|
|
|
Actions = actions.ToArray();
|
|
}
|
|
|
|
private async Task<bool> OnElementClicked(FileData fileData)
|
|
{
|
|
if (fileData.IsFile)
|
|
{
|
|
EditorInitialData = await Access.Read(fileData);
|
|
EditorLanguage = MonacoTypeHelper.GetEditorType(fileData.Name);
|
|
EditingFile = fileData;
|
|
|
|
Editing = true;
|
|
|
|
await InvokeAsync(StateHasChanged);
|
|
return true;
|
|
}
|
|
|
|
await InvokeAsync(StateHasChanged);
|
|
return false;
|
|
}
|
|
|
|
private async void Cancel(bool save = false)
|
|
{
|
|
if (save)
|
|
{
|
|
var data = await Editor.GetData();
|
|
await Access.Write(EditingFile, data);
|
|
}
|
|
|
|
Editing = false;
|
|
await InvokeAsync(StateHasChanged);
|
|
}
|
|
|
|
private async Task Launch()
|
|
{
|
|
var url = await Access.GetLaunchUrl();
|
|
NavigationManager.NavigateTo(url, true);
|
|
}
|
|
|
|
private async Task CreateFolder()
|
|
{
|
|
var name = await AlertService.Text(
|
|
SmartTranslateService.Translate("Create a new folder"),
|
|
SmartTranslateService.Translate("Enter a name"),
|
|
""
|
|
);
|
|
|
|
if (string.IsNullOrEmpty(name))
|
|
return;
|
|
|
|
await Access.MkDir(name);
|
|
await View!.Refresh();
|
|
}
|
|
|
|
private async Task OnSelectionChanged()
|
|
{
|
|
await InvokeAsync(StateHasChanged);
|
|
}
|
|
|
|
private async Task StartMoveFiles()
|
|
{
|
|
await FileSelectModal.Show();
|
|
}
|
|
|
|
private async Task DeleteMultiple()
|
|
{
|
|
foreach (var data in View!.SelectedFiles)
|
|
{
|
|
await Access.Delete(data);
|
|
}
|
|
|
|
await View!.Refresh();
|
|
}
|
|
|
|
private async Task CompressMultiple()
|
|
{
|
|
await Access.Compress(View!.SelectedFiles);
|
|
|
|
await View!.Refresh();
|
|
}
|
|
|
|
private async Task OnFileMoveSubmit(string path)
|
|
{
|
|
foreach (var sFile in View!.SelectedFiles)
|
|
{
|
|
await Access.Move(sFile, path + sFile.Name);
|
|
}
|
|
|
|
if (SingleMoveFile != null)
|
|
{
|
|
await Access.Move(SingleMoveFile, path + SingleMoveFile.Name);
|
|
SingleMoveFile = null;
|
|
}
|
|
|
|
await View.Refresh();
|
|
}
|
|
|
|
// This method can be called by every component to refresh the view
|
|
private async Task OnComponentStateChanged()
|
|
{
|
|
await View!.Refresh();
|
|
await InvokeAsync(StateHasChanged);
|
|
}
|
|
} |