Semi-functioning file selector component
parent
efda7bf03d
commit
74750b1dc9
|
@ -3,162 +3,107 @@
|
||||||
@using System.IO.Compression;
|
@using System.IO.Compression;
|
||||||
@inject ArchiveService ArchiveService;
|
@inject ArchiveService ArchiveService;
|
||||||
|
|
||||||
<div class="card-body">
|
<MudGrid>
|
||||||
<div class="row">
|
<MudItem xs="4">
|
||||||
<div class="col">
|
<MudTreeView Items="Root.Children" Hover="true" @bind-SelectedValue="SelectedDirectory" T="ArchiveDirectory">
|
||||||
<nav aria-label="breadcrumb">
|
<ItemTemplate>
|
||||||
<ol class="breadcrumb">
|
<MudTreeViewItem Value="@context" Items="@context.Children" Text="@context.Name" T="ArchiveDirectory" OnClick="() => ChangeDirectory(context)"></MudTreeViewItem>
|
||||||
@if (BreadCrumbs.Length == 0)
|
</ItemTemplate>
|
||||||
{
|
</MudTreeView>
|
||||||
<li class="breadcrumb-item active">Root</li>
|
</MudItem>
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
<li class="breadcrumb-item" @onclick="() => GoToRoot()">Root</li>
|
|
||||||
}
|
|
||||||
|
|
||||||
@for (int i = 0; i < BreadCrumbs.Length; i++)
|
<MudItem xs="8">
|
||||||
{
|
<MudTable Items="@CurrentPathEntries" Hover="true">
|
||||||
var path = String.Join('/', BreadCrumbs.Take(i + 1)) + '/';
|
<HeaderContent>
|
||||||
|
<MudTh></MudTh>
|
||||||
if (i == BreadCrumbs.Length - 1)
|
<MudTh>Name</MudTh>
|
||||||
{
|
<MudTh>Size</MudTh>
|
||||||
<li class="breadcrumb-item active">@BreadCrumbs[i]</li>
|
<MudTh>Modified</MudTh>
|
||||||
}
|
@if (OnFileSelected.HasDelegate)
|
||||||
else
|
|
||||||
{
|
|
||||||
<li class="breadcrumb-item" @onclick="() => GoToPath(path)">@BreadCrumbs[i]</li>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</ol>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="table-responsive">
|
|
||||||
<table class="table table-vcenter table-striped table-hover card-table" id="ArchiveBrowser">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th></th>
|
|
||||||
<th>Name</th>
|
|
||||||
<th>Size</th>
|
|
||||||
<th>Modified</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
@if (CurrentPath != "")
|
|
||||||
{
|
|
||||||
<tr @ondblclick="GoUpLevel">
|
|
||||||
<td></td>
|
|
||||||
<td colspan="3">..</td>
|
|
||||||
</tr>
|
|
||||||
}
|
|
||||||
|
|
||||||
@foreach (var entry in CurrentPathEntries.OrderBy(e => !e.FullName.EndsWith('/')).ThenBy(e => e.FullName))
|
|
||||||
{
|
|
||||||
@if (entry.FullName.EndsWith('/'))
|
|
||||||
{
|
{
|
||||||
<tr @ondblclick="() => GoToPath(entry.FullName)">
|
<MudTh></MudTh>
|
||||||
<td><i class="ti ti-@GetIcon(entry.FullName.ToLower())"></i></td>
|
|
||||||
<td>@entry.FullName.Remove(0, CurrentPath.Length)</td>
|
|
||||||
<td></td>
|
|
||||||
<td>@entry.LastWriteTime</td>
|
|
||||||
</tr>
|
|
||||||
}
|
}
|
||||||
else
|
</HeaderContent>
|
||||||
|
<RowTemplate>
|
||||||
|
<MudTd><MudIcon Icon="@GetIcon(context)" /></MudTd>
|
||||||
|
<MudTd>@GetFileName(context)</MudTd>
|
||||||
|
<MudTd>@ByteSize.FromBytes(context.Length)</MudTd>
|
||||||
|
<MudTd>@context.LastWriteTime</MudTd>
|
||||||
|
@if (OnFileSelected.HasDelegate)
|
||||||
{
|
{
|
||||||
<tr>
|
<MudTd><MudButton OnClick="() => OnFileSelected.InvokeAsync(context.FullName)">Select</MudButton></MudTd>
|
||||||
<td><i class="ti ti-@GetIcon(entry.FullName.ToLower())"></i></td>
|
|
||||||
<td>@entry.Name</td>
|
|
||||||
<td class="text-end">@ByteSize.FromBytes(entry.Length)</td>
|
|
||||||
<td>@entry.LastWriteTime</td>
|
|
||||||
</tr>
|
|
||||||
}
|
}
|
||||||
}
|
</RowTemplate>
|
||||||
</tbody>
|
</MudTable>
|
||||||
</table>
|
</MudItem>
|
||||||
</div>
|
</MudGrid>
|
||||||
|
|
||||||
<style>
|
|
||||||
.breadcrumb-item:not(.active) {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ArchiveBrowser tr {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ArchiveBrowser tr td:first-child {
|
|
||||||
padding: 0;
|
|
||||||
padding-left: .75rem;
|
|
||||||
font-size: 1.5rem;
|
|
||||||
width: .75rem;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
[Parameter] public Guid ArchiveId { get; set; }
|
[Parameter] public Guid ArchiveId { get; set; }
|
||||||
|
[Parameter] public Guid Archive { get; set; }
|
||||||
|
[Parameter] public EventCallback<string> OnFileSelected { get; set; }
|
||||||
|
|
||||||
|
|
||||||
private IEnumerable<ZipArchiveEntry> Entries { get; set; }
|
private IEnumerable<ZipArchiveEntry> Entries { get; set; }
|
||||||
private IEnumerable<ZipArchiveEntry> CurrentPathEntries { get; set; }
|
private IEnumerable<ZipArchiveEntry> CurrentPathEntries { get; set; }
|
||||||
private string CurrentPath { get; set; }
|
private string CurrentPath { get; set; }
|
||||||
private string[] BreadCrumbs { get { return CurrentPath.TrimEnd('/').Split('/'); } }
|
private ArchiveDirectory Root { get; set; }
|
||||||
|
private ArchiveDirectory SelectedDirectory { get; set; }
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
Entries = await ArchiveService.GetContents(ArchiveId);
|
Entries = await ArchiveService.GetContents(ArchiveId);
|
||||||
|
|
||||||
GoToRoot();
|
Root = new ArchiveDirectory()
|
||||||
}
|
|
||||||
|
|
||||||
private void GoToRoot()
|
|
||||||
{
|
|
||||||
CurrentPath = "";
|
|
||||||
CurrentPathEntries = Entries.Where(e => e.FullName.TrimEnd('/').Split('/').Length == 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void GoUpLevel()
|
|
||||||
{
|
|
||||||
var parts = CurrentPath.TrimEnd('/').Split('/');
|
|
||||||
|
|
||||||
if (parts.Length == 1)
|
|
||||||
GoToRoot();
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
GoToPath(String.Join('/', parts.Take(parts.Length - 1)) + "/");
|
Name = "/",
|
||||||
|
FullName = ""
|
||||||
|
};
|
||||||
|
|
||||||
|
Root.PopulateChildren(Entries);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ChangeDirectory(ArchiveDirectory selectedDirectory)
|
||||||
|
{
|
||||||
|
if (SelectedDirectory == null)
|
||||||
|
SelectedDirectory = selectedDirectory;
|
||||||
|
|
||||||
|
CurrentPathEntries = Entries.Where(e => e.FullName.StartsWith(SelectedDirectory.FullName) && e.FullName != SelectedDirectory.FullName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetFileName(ZipArchiveEntry entry)
|
||||||
|
{
|
||||||
|
if (String.IsNullOrWhiteSpace(entry.Name) && entry.Length == 0)
|
||||||
|
{
|
||||||
|
return entry.FullName.TrimEnd('/').Split('/').Last();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
return entry.Name;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GoToPath(string path)
|
private string GetIcon(ZipArchiveEntry entry)
|
||||||
{
|
{
|
||||||
CurrentPath = path;
|
switch (Path.GetExtension(entry.FullName))
|
||||||
CurrentPathEntries = Entries.Where(e => e.FullName.StartsWith(CurrentPath) && e.FullName != CurrentPath && e.FullName.Remove(0, path.Length).TrimEnd('/').Split('/').Length == 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetIcon(string path)
|
|
||||||
{
|
|
||||||
switch (Path.GetExtension(path))
|
|
||||||
{
|
{
|
||||||
case "":
|
case "":
|
||||||
return "folder";
|
return Icons.Material.Filled.Folder;
|
||||||
|
|
||||||
case ".exe":
|
case ".exe":
|
||||||
return "terminal-2";
|
return Icons.Material.Filled.Terminal;
|
||||||
|
|
||||||
case ".zip":
|
case ".zip":
|
||||||
case ".rar":
|
case ".rar":
|
||||||
case ".7z":
|
case ".7z":
|
||||||
case ".gz":
|
case ".gz":
|
||||||
case ".tar":
|
case ".tar":
|
||||||
return "file-zip";
|
return Icons.Material.Filled.FolderZip;
|
||||||
|
|
||||||
case ".wad":
|
case ".wad":
|
||||||
case ".pk3":
|
case ".pk3":
|
||||||
case ".pak":
|
case ".pak":
|
||||||
case ".cab":
|
case ".cab":
|
||||||
return "archive";
|
return Icons.Material.Filled.Token;
|
||||||
|
|
||||||
case ".txt":
|
case ".txt":
|
||||||
case ".cfg":
|
case ".cfg":
|
||||||
|
@ -169,12 +114,12 @@
|
||||||
case ".log":
|
case ".log":
|
||||||
case ".doc":
|
case ".doc":
|
||||||
case ".nfo":
|
case ".nfo":
|
||||||
return "file-text";
|
return Icons.Custom.FileFormats.FileDocument;
|
||||||
|
|
||||||
case ".bat":
|
case ".bat":
|
||||||
case ".ps1":
|
case ".ps1":
|
||||||
case ".json":
|
case ".json":
|
||||||
return "file-code";
|
return Icons.Custom.FileFormats.FileCode;
|
||||||
|
|
||||||
case ".bik":
|
case ".bik":
|
||||||
case ".avi":
|
case ".avi":
|
||||||
|
@ -186,26 +131,54 @@
|
||||||
case ".mpg":
|
case ".mpg":
|
||||||
case ".mpeg":
|
case ".mpeg":
|
||||||
case ".flv":
|
case ".flv":
|
||||||
return "movie";
|
return Icons.Custom.FileFormats.FileVideo;
|
||||||
|
|
||||||
case ".dll":
|
case ".dll":
|
||||||
return "package";
|
return Icons.Material.Filled.SettingsApplications;
|
||||||
|
|
||||||
case ".scm":
|
case ".scm":
|
||||||
return "map";
|
return Icons.Material.Filled.Map;
|
||||||
|
|
||||||
case ".hlp":
|
case ".hlp":
|
||||||
return "help";
|
return Icons.Material.Filled.Help;
|
||||||
|
|
||||||
case ".png":
|
case ".png":
|
||||||
case ".bmp":
|
case ".bmp":
|
||||||
case ".jpeg":
|
case ".jpeg":
|
||||||
case ".jpg":
|
case ".jpg":
|
||||||
case ".gif":
|
case ".gif":
|
||||||
return "photo";
|
return Icons.Custom.FileFormats.FileImage;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return "file";
|
return Icons.Material.Filled.InsertDriveFile;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ArchiveDirectory
|
||||||
|
{
|
||||||
|
public string Name { get; set; }
|
||||||
|
public string FullName { get; set; }
|
||||||
|
public bool IsExpanded { get; set; } = false;
|
||||||
|
public bool HasChildren => Children != null && Children.Count > 0;
|
||||||
|
public HashSet<ArchiveDirectory> Children { get; set; } = new HashSet<ArchiveDirectory>();
|
||||||
|
|
||||||
|
public void PopulateChildren(IEnumerable<ZipArchiveEntry> entries)
|
||||||
|
{
|
||||||
|
var childPaths = entries.Where(e => e.FullName.StartsWith(FullName) && e.FullName.EndsWith('/'));
|
||||||
|
var directChildren = childPaths.Where(p => p.FullName != FullName && p.FullName.Substring(FullName.Length + 1).TrimEnd('/').Split('/').Length == 1);
|
||||||
|
|
||||||
|
foreach (var directChild in directChildren)
|
||||||
|
{
|
||||||
|
var child = new ArchiveDirectory()
|
||||||
|
{
|
||||||
|
FullName = directChild.FullName,
|
||||||
|
Name = directChild.FullName.Substring(FullName.Length).TrimEnd('/')
|
||||||
|
};
|
||||||
|
|
||||||
|
child.PopulateChildren(entries);
|
||||||
|
|
||||||
|
Children.Add(child);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
<MudDialog>
|
||||||
|
<TitleContent>
|
||||||
|
<MudText Typo="Typo.h6">
|
||||||
|
Select a File
|
||||||
|
</MudText>
|
||||||
|
</TitleContent>
|
||||||
|
|
||||||
|
<DialogContent>
|
||||||
|
<MudContainer Style="overflow-y: scroll">
|
||||||
|
<ArchiveBrowser ArchiveId="ArchiveId" OnFileSelected="FileSelected" />
|
||||||
|
</MudContainer>
|
||||||
|
</DialogContent>
|
||||||
|
|
||||||
|
<DialogActions>
|
||||||
|
<MudButton OnClick="Cancel">Cancel</MudButton>
|
||||||
|
</DialogActions>
|
||||||
|
</MudDialog>
|
||||||
|
|
||||||
|
@code {
|
||||||
|
[CascadingParameter] MudDialogInstance MudDialog { get; set; }
|
||||||
|
[Parameter] public Guid ArchiveId { get; set; }
|
||||||
|
|
||||||
|
protected override async Task OnInitializedAsync()
|
||||||
|
{
|
||||||
|
MudDialog.Options.MaxWidth = MaxWidth.Large;
|
||||||
|
MudDialog.Options.FullWidth = true;
|
||||||
|
MudDialog.Options.FullScreen = true;
|
||||||
|
|
||||||
|
MudDialog.SetOptions(MudDialog.Options);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Cancel()
|
||||||
|
{
|
||||||
|
MudDialog.Cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void FileSelected(string fileName)
|
||||||
|
{
|
||||||
|
MudDialog.Close(DialogResult.Ok(fileName));
|
||||||
|
}
|
||||||
|
}
|
|
@ -68,9 +68,22 @@
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void BrowseForIcon()
|
private async void BrowseForIcon()
|
||||||
{
|
{
|
||||||
|
var parameters = new DialogParameters
|
||||||
|
{
|
||||||
|
["ArchiveId"] = Game.Archives.OrderByDescending(a => a.CreatedOn).First().Id
|
||||||
|
};
|
||||||
|
|
||||||
|
var dialog = await DialogService.ShowAsync<ArchiveFileSelector>("File Selector", parameters);
|
||||||
|
var result = await dialog.Result;
|
||||||
|
|
||||||
|
if (!result.Canceled)
|
||||||
|
{
|
||||||
|
Game.Icon = result.Data as string;
|
||||||
|
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void LookupGameMetadata()
|
private async void LookupGameMetadata()
|
||||||
|
|
Loading…
Reference in New Issue