123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241 |
- @inherits ViewBase
- @code {
- private Dictionary<string, string> AllTrackSet;
- private string searchExpression { get => LocalStorage.Get<string>(); set => LocalStorage.Set(value); }
- private string searchTrackSetKey { get => LocalStorage.Get<string>() ?? "main"; set => LocalStorage.Set(value); }
- private int searchLimitCount { get => LocalStorage.Get<int?>() ?? 20; set => LocalStorage.Set(value); }
- private bool isSearching = false;
- private ProgressBar searchProgressBar;
- private static string resultText;
- private static IGrouping<FeDisc, FeTrack>[] resultEntries;
- private DiscDialog dlgDisc;
- private PlaylistAddDialog dlgPlaylistAdd;
- }
- <DiscDialog @ref="dlgDisc" Disc="CurrentDisc"></DiscDialog>
- <PlaylistAddDialog @ref="dlgPlaylistAdd"></PlaylistAddDialog>
- <div class="row">
- <div class="col-12">
- <fieldset class="border rounded-3 p-2">
- <legend class="float-none w-auto px-2 d-flex flex-row align-items-center">
- <span>Filter</span>
- </legend>
- <div class="input-group">
- <div class="form-floating">
- <InputText type="search" class="form-control" placeholder="Search expression"
- Value="@searchExpression"
- ValueExpression="@(()=>searchExpression)"
- @oninput="SearchChanged"
- onsearch="@SearchGo">
- </InputText>
- <label>Search expression</label>
- </div>
- <button @onclick="@SearchGo" class="btn btn-outline-primary" type="button">Search</button>
- </div>
- <div class="row mt-3">
- <label for="staticEmail" class="col-sm-2 col-form-label">Track set</label>
- <div class="col-sm-10">
- <InputRadioGroup @bind-Value="TrackSetKeyProperty">
- <div class="btn-group" role="group" aria-label="Basic radio toggle button group">
- @foreach (var item in AllTrackSet.KeepNoEmpty().WithIndex())
- {
- <InputRadio class="btn-check" id="@("stk-"+item.index)" Value="item.item.Key"></InputRadio>
- <label class="btn btn-outline-primary" for="@("stk-"+item.index)">@(item.item.Value)</label>
- }
- </div>
- </InputRadioGroup>
- </div>
- </div>
- <div class="row mt-3">
- <label for="staticEmail" class="col-sm-2 col-form-label">Result count</label>
- <div class="col-sm-10">
- <InputRadioGroup @bind-Value="ResultCountProperty">
- <div class="btn-group" role="group" aria-label="Basic radio toggle button group">
- @foreach (var lc in new[] { 20, 50, 100, 200 })
- {
- <InputRadio class="btn-check" id="@($"limit-count-{lc}")" Value="@lc"></InputRadio>
- <label class="btn btn-outline-primary" for="@($"limit-count-{lc}")">@lc</label>
- }
- </div>
- </InputRadioGroup>
- </div>
- </div>
- @*<div class="row mt-3">
- <label for="staticEmail" class="col-sm-2 col-form-label">Debug</label>
- <div class="col-sm-10">
- <button class="btn btn-primary" @onclick="()=>isSearching=true">Show progressbar</button>
- </div>
- </div>*@
- </fieldset>
- </div>
- </div>
- @if (isSearching)
- {
- <div class="row mt-4">
- <div class="col-12">
- <div class="btn-group w-100">
- <ProgressBar @ref="searchProgressBar" Throttle="333" class="btn border w-75"></ProgressBar>
- <button class="btn border btn-danger" @onclick="()=>isSearching=false">Stop search</button>
- </div>
- </div>
- </div>
- }
- <div class="row mt-3">
- <div class="col-12">
- <fieldset class="border rounded-3 p-2">
- <legend class="float-none w-auto px-2 d-flex flex-row align-items-center">
- <span>Result</span>
- </legend>
- <div class="mb-3 text-center">@resultText</div>
- @if (resultEntries?.Length > 0)
- {
- foreach (var item in resultEntries)
- {
- var disc = item.Key;
- <div class="table-responsive">
- <table class="table w-100">
- <tbody>
- <tr class="table-primary">
- <td><img src="@disc.CoverPath" style="height:50px" /></td>
- <td colspan="2" class="w-100">
- <div class="text-nowrap">@item.Key.Name</div>
- <div class="text-nowrap text-muted">@item.Key.Lib.Name</div>
- </td>
- <td colspan="2" class="text-end">
- <button class="btn btn-primary" @onclick="()=>dlgDisc.Show(disc)">
- <i class="bi bi-window-stack"></i>
- </button>
- </td>
- </tr>
- @foreach (var tr in item.OrderBy(p => p.Name))
- {
- <tr class="mouse-hilight">
- <td class="align-middle"><FileIcon Track="@tr" ShowParam="true"></FileIcon></td>
- <td class="w-100 text-nowrap">
- <div>
- <a href="@tr.Path" target="@FnzConst.PlayPageTarget">
- <HighLightKeyword Text="@tr.GetTitleOrFilename()" Keywords="@(new []{ searchExpression})"></HighLightKeyword>
- </a>
- </div>
- <div class="text-nowrap text-muted">@tr.Tag?.Artist</div>
- </td>
- <td>
- <div class="text-nowrap">@tr.Tag.Duration.SecondToDur()</div>
- <div class="text-nowrap text-muted">@tr.Tag.Length.BytesToFileSize()</div>
- </td>
- <td class="text-center">
- <button type="button" class="btn btn-link" style="padding:0.1rem" @onclick="()=>dlgPlaylistAdd.Show(tr)">
- <i class="bi bi-folder-plus"></i>
- </button>
- </td>
- </tr>
- }
- </tbody>
- </table>
- </div>
- }
- }
- </fieldset>
- </div>
- </div>
- @code {
- private async Task SearchGo()
- {
- isSearching = true;
- StateHasChanged();
- await Task.Delay(1);
- var filteredList = new List<FeTrack>(searchLimitCount);
- var matchedCount = 0;
- var flagPlus = false;
- var filters = new List<Func<FeTrack, bool>> { p => p.TrackSetKey == searchTrackSetKey };
- //TODO: Expression implement
- if (string.IsNullOrEmpty(searchExpression) == false)
- {
- filters.Add(p => p.GetTitleOrFilename().Contains(searchExpression, StringComparison.OrdinalIgnoreCase));
- }
- for (var i = 0; i < DataSet.AllTracks.Length && isSearching; i++)
- {
- var item = DataSet.AllTracks[i];
- if (filters.All(p => p(item)))
- {
- ++matchedCount;
- if (filteredList.Count < searchLimitCount)
- {
- filteredList.Add(item);
- }
- else if (matchedCount >= searchLimitCount * 2)
- {
- flagPlus = true;
- break;
- }
- }
- await searchProgressBar.SetProgress((float)i / DataSet.AllTracks.Length, $"Searching {i + 1}/{DataSet.AllTracks.Length} matched:{matchedCount}");
- }
- //TODO: search in disc name
- resultText = $"Result for {searchExpression.NullOrEmptyEscape("<NONE>")} on {DataSet.AllTracksSet.Where(p => p.Key == searchTrackSetKey).Select(p => p.Name).FirstOrDefault() ?? "?"} limit {searchLimitCount} of {matchedCount}{(flagPlus ? "+" : "")}";
- resultEntries = filteredList
- .GroupBy(p => p.Disc)
- .ToArray();
- isSearching = false;
- StateHasChanged();
- }
- protected override async Task OnAfterRenderAsync(bool firstRender)
- {
- await base.OnAfterRenderAsync(firstRender);
- if (firstRender)
- {
- AllTrackSet = DataSet.AllTracksSet.GroupBy(p => p.Key).ToDictionary(p => p.Key, p => p.First().Name);
- if (resultEntries == null) await SearchGo();
- else StateHasChanged();
- }
- }
- private void SearchChanged(ChangeEventArgs e)
- {
- searchExpression = e.Value.ToString().Trim();
- }
- public string TrackSetKeyProperty
- {
- get => searchTrackSetKey;
- set
- {
- if (searchTrackSetKey == value) return;
- searchTrackSetKey = value;
- SearchGo();
- }
- }
- public int ResultCountProperty
- {
- get => searchLimitCount;
- set
- {
- if (searchLimitCount == value) return;
- searchLimitCount = value;
- SearchGo();
- }
- }
- }
|