Show import progress in popover
This commit is contained in:
parent
ba06b56dc3
commit
98bfe90605
10 changed files with 227 additions and 49 deletions
9
LANCommander.Launcher.Models/ImportProgress.cs
Normal file
9
LANCommander.Launcher.Models/ImportProgress.cs
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
namespace LANCommander.Launcher.Models;
|
||||
|
||||
public class ImportProgress
|
||||
{
|
||||
public int Index { get; set; }
|
||||
public int Total { get; set; }
|
||||
public ImportItem CurrentItem { get; set; }
|
||||
public bool IsImporting { get; set; }
|
||||
}
|
||||
|
|
@ -59,6 +59,7 @@ namespace LANCommander.Launcher.Services.Extensions
|
|||
services.AddSingleton<KeepAliveService>();
|
||||
#endregion
|
||||
|
||||
services.AddSingleton<ImportManagerService>();
|
||||
services.AddScoped<CollectionService>();
|
||||
services.AddScoped<CommandLineService>();
|
||||
services.AddScoped<CompanyService>();
|
||||
|
|
|
|||
22
LANCommander.Launcher.Services/ImportManagerService.cs
Normal file
22
LANCommander.Launcher.Services/ImportManagerService.cs
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
using System.Threading.Tasks;
|
||||
|
||||
namespace LANCommander.Launcher.Services;
|
||||
|
||||
public class ImportManagerService
|
||||
{
|
||||
private readonly ImportService ImportService;
|
||||
|
||||
public ImportManagerService(ImportService importService)
|
||||
{
|
||||
ImportService = importService;
|
||||
}
|
||||
|
||||
public delegate Task OnImportRequestedHandler();
|
||||
public event OnImportRequestedHandler OnImportRequested;
|
||||
|
||||
public async Task RequestImport()
|
||||
{
|
||||
if (OnImportRequested != null)
|
||||
await OnImportRequested.Invoke();
|
||||
}
|
||||
}
|
||||
|
|
@ -40,6 +40,9 @@ namespace LANCommander.Launcher.Services
|
|||
private readonly Settings Settings;
|
||||
private readonly DatabaseContext DatabaseContext;
|
||||
|
||||
private ImportProgress _importProgress = new();
|
||||
public ImportProgress Progress => _importProgress;
|
||||
|
||||
public delegate Task OnImportUpdatedHandler(ImportStatusUpdate update);
|
||||
public event OnImportUpdatedHandler OnImportUpdated;
|
||||
|
||||
|
|
@ -369,9 +372,11 @@ namespace LANCommander.Launcher.Services
|
|||
{
|
||||
var library = await LibraryService.GetByUserAsync(AuthenticationService.GetUserId());
|
||||
|
||||
Logger?.LogInformation("Importing games");
|
||||
Logger?.LogInformation("Starting library import");
|
||||
|
||||
int i = 1;
|
||||
_importProgress.IsImporting = true;
|
||||
_importProgress.Index = 1;
|
||||
_importProgress.Total = games.Count();
|
||||
|
||||
foreach (var game in games)
|
||||
{
|
||||
|
|
@ -379,13 +384,17 @@ namespace LANCommander.Launcher.Services
|
|||
{
|
||||
var remoteGame = await Client.Games.GetAsync(game.Id);
|
||||
|
||||
_importProgress.CurrentItem = new ImportItem(game.Id, game.Name);
|
||||
|
||||
if (OnImportUpdated != null)
|
||||
await OnImportUpdated(new ImportStatusUpdate
|
||||
{
|
||||
await OnImportUpdated.Invoke(new ImportStatusUpdate
|
||||
{
|
||||
CurrentItem = new ImportItem(game.Id, game.Name),
|
||||
Index = i,
|
||||
Total = games.Count()
|
||||
Index = _importProgress.Index,
|
||||
Total = _importProgress.Total,
|
||||
CurrentItem = _importProgress.CurrentItem
|
||||
});
|
||||
}
|
||||
|
||||
if (game != null && remoteGame != null)
|
||||
{
|
||||
|
|
@ -402,9 +411,13 @@ namespace LANCommander.Launcher.Services
|
|||
}
|
||||
finally
|
||||
{
|
||||
i++;
|
||||
_importProgress.Index++;
|
||||
}
|
||||
}
|
||||
|
||||
_importProgress.IsImporting = false;
|
||||
if (OnImportComplete != null)
|
||||
await OnImportComplete.Invoke();
|
||||
|
||||
Logger?.LogInformation("Importing games completed");
|
||||
}
|
||||
|
|
|
|||
36
LANCommander.Launcher/Styles/_import.scss
vendored
Normal file
36
LANCommander.Launcher/Styles/_import.scss
vendored
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
.import-progress {
|
||||
width: 300px;
|
||||
|
||||
&-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
&-status {
|
||||
position: relative;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
max-width: 100%;
|
||||
font-size: 14px;
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
height: 100%;
|
||||
width: 32px;
|
||||
background: linear-gradient(to right, rgba(31, 31, 31, 0), rgb(31, 31, 31, 1) 90%);
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
&-progress-bar {
|
||||
margin: 4px 0;
|
||||
}
|
||||
|
||||
&-footer {
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
|
@ -23,4 +23,5 @@
|
|||
@import '_download-queue';
|
||||
@import '_game-actions-dialog';
|
||||
@import '_install-dialog';
|
||||
@import '_checkbox-button-group';
|
||||
@import '_checkbox-button-group';
|
||||
@import '_import';
|
||||
|
|
@ -4,6 +4,7 @@
|
|||
@inject NavigationManager NavigationManager
|
||||
@inject IMessageService MessageService
|
||||
@inject ILogger<LoginForm> Logger
|
||||
@inject ImportManagerService ImportManagerService
|
||||
|
||||
<PageHeader OnBack="OnBack">
|
||||
<TitleTemplate>
|
||||
|
|
@ -100,9 +101,11 @@
|
|||
{
|
||||
await AuthenticationService.Login(Client.GetServerAddress(), Model.UserName, Model.Password);
|
||||
|
||||
MainLayout.Import();
|
||||
await ImportManagerService.RequestImport();
|
||||
|
||||
NavigationManager.NavigateTo("/");
|
||||
|
||||
MessageService.Success("Welcome back!");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
|
@ -128,7 +131,7 @@
|
|||
{
|
||||
await AuthenticationService.Login(ServerAddress, token);
|
||||
|
||||
MainLayout.Import();
|
||||
await ImportManagerService.RequestImport();
|
||||
|
||||
NavigationManager.NavigateTo("/");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
@inject NavigationManager NavigationManager
|
||||
@inject IMessageService MessageService
|
||||
@inject ILogger<RegistrationForm> Logger
|
||||
@inject ImportManagerService ImportManagerService
|
||||
|
||||
<PageHeader OnBack="OnBack">
|
||||
<TitleTemplate>
|
||||
|
|
@ -54,7 +55,7 @@
|
|||
{
|
||||
await AuthenticationService.Register(Client.GetServerAddress(), Model.UserName, Model.Password, Model.PasswordConfirmation);
|
||||
|
||||
MainLayout.Import();
|
||||
await ImportManagerService.RequestImport();
|
||||
|
||||
NavigationManager.NavigateTo("/");
|
||||
}
|
||||
|
|
@ -75,7 +76,7 @@
|
|||
{
|
||||
await AuthenticationService.Login(ServerAddress, token);
|
||||
|
||||
MainLayout.Import();
|
||||
await ImportManagerService.RequestImport();
|
||||
|
||||
NavigationManager.NavigateTo("/");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,37 @@
|
|||
@using LANCommander.Launcher.Models
|
||||
@inject ImportService ImportService
|
||||
|
||||
<div class="import-progress">
|
||||
<div class="import-progress-container">
|
||||
<Flex Vertical>
|
||||
<div class="import-progress-info">
|
||||
<div class="import-progress-status">
|
||||
@if (Total > 0)
|
||||
{
|
||||
<Text>Importing: @(CurrentItem?.Name ?? "")</Text>
|
||||
}
|
||||
else
|
||||
{
|
||||
<Text>Starting import...</Text>
|
||||
}
|
||||
</div>
|
||||
<div class="import-progress-progress-bar">
|
||||
<Progress
|
||||
Percent="@((double)(Index * 100) / Total)"
|
||||
Status="ProgressStatus.Active"
|
||||
ShowInfo="false"
|
||||
/>
|
||||
</div>
|
||||
<div class="import-progress-footer">
|
||||
@Index / @Total
|
||||
</div>
|
||||
</div>
|
||||
</Flex>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@code {
|
||||
[Parameter] public int Index { get; set; }
|
||||
[Parameter] public int Total { get; set; }
|
||||
[Parameter] public ImportItem CurrentItem { get; set; }
|
||||
}
|
||||
|
|
@ -12,6 +12,8 @@
|
|||
@inject ModalService ModalService
|
||||
@inject LANCommander.SDK.Client LANCommander
|
||||
@inject IJSRuntime JS
|
||||
@inject ILogger<MainLayout> Logger
|
||||
@inject ImportManagerService ImportManagerService
|
||||
|
||||
<CustomWindow HeaderHeight="37">
|
||||
<HeaderExtraControlsLayout>
|
||||
|
|
@ -19,14 +21,25 @@
|
|||
<AuthenticatedView>
|
||||
<Authenticated>
|
||||
<SpaceItem>
|
||||
<Popover Placement="Placement.BottomRight" IsButton OnClick="Import" Trigger="new[] { Trigger.Hover }">
|
||||
<ChildContent>
|
||||
<Button Type="@ButtonType.Text" Icon="@IconType.Outline.Sync" Loading="@Importing"/>
|
||||
</ChildContent>
|
||||
<ContentTemplate>
|
||||
<Progress Percent="@((ImportStatusIndex / (float)ImportStatusTotal) * 100)" Steps="@ImportStatusTotal"/>
|
||||
</ContentTemplate>
|
||||
</Popover>
|
||||
@if (Importing)
|
||||
{
|
||||
<Popover Placement="Placement.BottomRight" IsButton Trigger="new[] { Trigger.Hover }">
|
||||
<ChildContent>
|
||||
<Button Type="@ButtonType.Text" Icon="@IconType.Outline.Sync" Loading="@Importing"/>
|
||||
</ChildContent>
|
||||
<ContentTemplate>
|
||||
<ImportProgressDisplay
|
||||
Index="@ImportStatusIndex"
|
||||
Total="@ImportStatusTotal"
|
||||
CurrentItem="@(_importProgress?.CurrentItem)"
|
||||
/>
|
||||
</ContentTemplate>
|
||||
</Popover>
|
||||
}
|
||||
else
|
||||
{
|
||||
<Button Type="@ButtonType.Text" Icon="@IconType.Outline.Sync" OnClick="@Import"/>
|
||||
}
|
||||
</SpaceItem>
|
||||
|
||||
<SpaceItem>
|
||||
|
|
@ -82,8 +95,6 @@
|
|||
|
||||
public IMessageService Messages { get; set; }
|
||||
|
||||
public static MainLayout _MainLayout { get; set; }
|
||||
|
||||
string RandomQuip = "";
|
||||
|
||||
string[] CrashQuips = new[]
|
||||
|
|
@ -120,38 +131,44 @@
|
|||
int ImportStatusIndex = 0;
|
||||
int ImportStatusTotal = 0;
|
||||
|
||||
private ImportProgress _importProgress => ImportService.Progress;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
_MainLayout = this;
|
||||
|
||||
Settings = SettingService.GetSettings();
|
||||
Messages = MessageService;
|
||||
|
||||
ImportService.OnImportComplete += OnImportComplete;
|
||||
ImportService.OnImportUpdated += OnImportUpdated;
|
||||
|
||||
ImportManagerService.OnImportRequested += Import;
|
||||
AuthenticationService.OnOfflineModeChanged += OnOfflineModeChanged;
|
||||
|
||||
var randIndex = new Random().Next(0, CrashQuips.Length - 1);
|
||||
|
||||
RandomQuip = CrashQuips[randIndex];
|
||||
}
|
||||
|
||||
async Task OnImportComplete()
|
||||
public void Dispose()
|
||||
{
|
||||
MessageService.Success("Import Complete", 3);
|
||||
}
|
||||
if (AuthenticationService != null)
|
||||
{
|
||||
AuthenticationService.OnOfflineModeChanged -= OnOfflineModeChanged;
|
||||
}
|
||||
|
||||
async Task OnImportUpdated(ImportStatusUpdate status)
|
||||
{
|
||||
MessageService.Info($"Importing {status.CurrentItem.Name}");
|
||||
if (ImportService != null)
|
||||
{
|
||||
ImportService.OnImportComplete -= OnImportCompleteHandler;
|
||||
ImportService.OnImportUpdated -= OnImportUpdatedHandler;
|
||||
}
|
||||
|
||||
if (ImportManagerService != null)
|
||||
{
|
||||
ImportManagerService.OnImportRequested -= Import;
|
||||
}
|
||||
}
|
||||
|
||||
async void OnOfflineModeChanged(bool state)
|
||||
{
|
||||
_MainLayout.ConnectionState.OfflineModeEnabled = state;
|
||||
_MainLayout.ConnectionState.IsConnected = LANCommander.IsConnected();
|
||||
await InvokeAsync(_MainLayout.StateHasChanged);
|
||||
ConnectionState.OfflineModeEnabled = state;
|
||||
ConnectionState.IsConnected = LANCommander.IsConnected();
|
||||
await InvokeAsync(StateHasChanged);
|
||||
}
|
||||
|
||||
async Task CopyError(Exception ex)
|
||||
|
|
@ -222,23 +239,61 @@
|
|||
NavigationManager.NavigateTo("/Authenticate");
|
||||
}
|
||||
|
||||
public static async void Import()
|
||||
public async Task Import()
|
||||
{
|
||||
if (!_MainLayout.Importing)
|
||||
if (!Importing)
|
||||
{
|
||||
await _MainLayout.JS.InvokeVoidAsync("window.external.sendMessage", "import");
|
||||
Logger?.LogInformation("Starting import process");
|
||||
|
||||
_MainLayout.Importing = true;
|
||||
_MainLayout.StateHasChanged();
|
||||
_MainLayout.MessageService.Info("Import Started", 2.5);
|
||||
// Clear any existing handlers
|
||||
ImportService.OnImportComplete -= OnImportCompleteHandler;
|
||||
ImportService.OnImportUpdated -= OnImportUpdatedHandler;
|
||||
|
||||
// Add our handlers
|
||||
ImportService.OnImportComplete += OnImportCompleteHandler;
|
||||
ImportService.OnImportUpdated += OnImportUpdatedHandler;
|
||||
|
||||
// Now start the import process
|
||||
Importing = true;
|
||||
ImportStatusIndex = 0;
|
||||
ImportStatusTotal = 0;
|
||||
await InvokeAsync(StateHasChanged);
|
||||
MessageService.Info("Import Started", 2.5);
|
||||
|
||||
Logger?.LogInformation("Starting import");
|
||||
await ImportService.ImportLibraryAsync(); // Call directly instead of using JS
|
||||
}
|
||||
}
|
||||
|
||||
[JSInvokable("ImportComplete")]
|
||||
public static void ImportComplete()
|
||||
private async Task OnImportCompleteHandler()
|
||||
{
|
||||
_MainLayout.Importing = false;
|
||||
_MainLayout.StateHasChanged();
|
||||
_MainLayout.ImportService.ImportHasCompleted();
|
||||
Logger?.LogInformation("Import Complete handler called");
|
||||
Importing = false;
|
||||
ImportStatusIndex = 0;
|
||||
ImportStatusTotal = 0;
|
||||
MessageService.Success("Import Complete", 3);
|
||||
await InvokeAsync(StateHasChanged);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task OnImportUpdatedHandler(ImportStatusUpdate status)
|
||||
{
|
||||
Logger?.LogInformation("Import Update handler called: {Index}/{Total}",
|
||||
status.Index, status.Total);
|
||||
ImportStatusIndex = status.Index;
|
||||
ImportStatusTotal = status.Total;
|
||||
await InvokeAsync(StateHasChanged);
|
||||
}
|
||||
}
|
||||
|
||||
<style>
|
||||
.import-progress {
|
||||
width: 300px; /* Fixed width */
|
||||
}
|
||||
|
||||
.import-progress .downloader-current-upper-status {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
max-width: 100%;
|
||||
}
|
||||
</style>
|
||||
Loading…
Add table
Add a link
Reference in a new issue