mirror of
https://github.com/wabbajack-tools/wabbajack.git
synced 2024-08-30 18:42:17 +00:00
Restructure installing stage into three pages. Changed some design.
Added getBlobUrlFromStream JavaScript function so we can reuse the URL.
This commit is contained in:
parent
d1e64e910c
commit
47ffa30222
@ -28,7 +28,7 @@
|
||||
{
|
||||
{"Play", Play.Route},
|
||||
{"Gallery", Gallery.Route},
|
||||
{"Install", Install.Route},
|
||||
{"Install", Select.Route},
|
||||
{"Create", Create.Route}
|
||||
};
|
||||
|
||||
|
@ -1,79 +0,0 @@
|
||||
@page "/configure"
|
||||
@using Wabbajack.App.Blazor.State
|
||||
|
||||
@namespace Wabbajack.App.Blazor.Pages
|
||||
|
||||
<div id="content">
|
||||
<div class="install-background">
|
||||
<img id="background-image" src="" alt=""/>
|
||||
</div>
|
||||
<div class="list">
|
||||
@if (Modlist is not null)
|
||||
{
|
||||
<div class="left-side">
|
||||
@if (InstallState != InstallState.Installing)
|
||||
{
|
||||
<InfoBlock Title="@Modlist.Name" Subtitle="@Modlist.Author" Comment="@Modlist.Version.ToString()" Description="@Modlist.Description"/>
|
||||
}
|
||||
else
|
||||
{
|
||||
<InfoBlock Supertitle="Installing..." Title="@Modlist.Name" Subtitle="@StatusText"/>
|
||||
// TODO: [Low] Step logging
|
||||
}
|
||||
</div>
|
||||
<div class="right-side">
|
||||
@* TODO: whatever this is *@
|
||||
@* @if (!string.IsNullOrEmpty(Image)) *@
|
||||
@* { *@
|
||||
@* if (InstallState != GlobalState.InstallStateEnum.Installing) *@
|
||||
@* { *@
|
||||
@* <InfoImage Image="@Image"/> *@
|
||||
@* } *@
|
||||
@* else if (InstallState == GlobalState.InstallStateEnum.Installing) *@
|
||||
@* { *@
|
||||
@* // TODO: [Low] Implement featured mod slideshow. *@
|
||||
@* <InfoImage Image="@Image" Title="Some Mod Title" Subtitle="Author and others" Description="This mod adds something cool but I'm not going to tell you anything."/> *@
|
||||
@* } *@
|
||||
@* } *@
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
@if (InstallState == InstallState.Installing)
|
||||
{
|
||||
<div class="logger-container">
|
||||
<VirtualLogger/>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="settings">
|
||||
<div class="locations">
|
||||
@* TODO: [High] Turn path selectors into components. *@
|
||||
<div class="labels">
|
||||
<span>Target Modlist</span>
|
||||
<span>Install Location</span>
|
||||
<span>Download Location</span>
|
||||
</div>
|
||||
<div class="paths">
|
||||
<span class="modlist-file">@ModlistPath.ToString()</span>
|
||||
<span class="install-location" @onclick="SelectInstallFolder">@InstallPath.ToString()</span>
|
||||
<span class="download-location" @onclick="SelectDownloadFolder">@DownloadPath.ToString()</span>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="options">
|
||||
<OptionCheckbox Label="Overwrite Installation"/>
|
||||
<OptionCheckbox Label="NTFS Compression"/>
|
||||
<OptionCheckbox Label="Do a sweet trick"/>
|
||||
<OptionCheckbox Label="Something else"/>
|
||||
</div>
|
||||
<div class="install">
|
||||
<img src="images/icons/play.svg" @onclick="Install" alt="Browse Gallery">
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
@code {
|
||||
public const string Route = "/configure";
|
||||
}
|
48
Wabbajack.App.Blazor/Pages/Install/Configure.razor
Normal file
48
Wabbajack.App.Blazor/Pages/Install/Configure.razor
Normal file
@ -0,0 +1,48 @@
|
||||
@page "/install/configure"
|
||||
|
||||
@namespace Wabbajack.App.Blazor.Pages
|
||||
|
||||
<div id="content">
|
||||
<div class="install-background">
|
||||
<img id="background-image" src="@ModlistImage" alt=""/>
|
||||
</div>
|
||||
<div class="list">
|
||||
@if (Modlist is not null)
|
||||
{
|
||||
<div class="left-side">
|
||||
<InfoBlock Title="@Modlist.Name" Subtitle="@Modlist.Author" Comment="@Modlist.Version.ToString()" Description="@Modlist.Description"/>
|
||||
</div>
|
||||
<div class="right-side">
|
||||
<InfoImage Image="@ModlistImage"/>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
<div class="settings">
|
||||
<div class="locations">
|
||||
<div class="labels">
|
||||
<span>Target Modlist</span>
|
||||
<span>Install Location</span>
|
||||
<span>Download Location</span>
|
||||
</div>
|
||||
<div class="paths">
|
||||
<span class="modlist-file">@ModlistPath.ToString()</span>
|
||||
<span class="install-location" @onclick="SelectInstallFolder">@InstallPath.ToString()</span>
|
||||
<span class="download-location" @onclick="SelectDownloadFolder">@DownloadPath.ToString()</span>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="options">
|
||||
<OptionCheckbox Label="Overwrite Installation"/>
|
||||
<OptionCheckbox Label="NTFS Compression"/>
|
||||
<OptionCheckbox Label="Do a sweet trick"/>
|
||||
<OptionCheckbox Label="Something else"/>
|
||||
</div>
|
||||
<div class="install">
|
||||
<img src="images/icons/play.svg" @onclick="Install" alt="Install">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@code {
|
||||
public const string Route = "/install/configure";
|
||||
}
|
131
Wabbajack.App.Blazor/Pages/Install/Configure.razor.cs
Normal file
131
Wabbajack.App.Blazor/Pages/Install/Configure.razor.cs
Normal file
@ -0,0 +1,131 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Wabbajack.DTOs;
|
||||
using Wabbajack.DTOs.JsonConverters;
|
||||
using Wabbajack.Installer;
|
||||
using Wabbajack.Paths;
|
||||
using Wabbajack.App.Blazor.Utility;
|
||||
using Wabbajack.Hashing.xxHash64;
|
||||
using Wabbajack.Services.OSIntegrated;
|
||||
using System.Threading.Tasks;
|
||||
using Blazored.Toast.Services;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.JSInterop;
|
||||
using Wabbajack.App.Blazor.State;
|
||||
|
||||
namespace Wabbajack.App.Blazor.Pages;
|
||||
|
||||
public partial class Configure
|
||||
{
|
||||
[Inject] private ILogger<Configure> Logger { get; set; } = default!;
|
||||
[Inject] private IStateContainer StateContainer { get; set; } = default!;
|
||||
[Inject] private DTOSerializer DTOs { get; set; } = default!;
|
||||
[Inject] private SettingsManager SettingsManager { get; set; } = default!;
|
||||
[Inject] private NavigationManager NavigationManager { get; set; } = default!;
|
||||
[Inject] private IJSRuntime JSRuntime { get; set; } = default!;
|
||||
[Inject] private IToastService toastService { get; set; }
|
||||
|
||||
private ModList? Modlist => StateContainer.Modlist;
|
||||
private string ModlistImage => StateContainer.ModlistImage;
|
||||
private AbsolutePath ModlistPath => StateContainer.ModlistPath;
|
||||
private AbsolutePath InstallPath => StateContainer.InstallPath;
|
||||
private AbsolutePath DownloadPath => StateContainer.DownloadPath;
|
||||
|
||||
private InstallState InstallState => StateContainer.InstallState;
|
||||
|
||||
private const string InstallSettingsPrefix = "install-settings-";
|
||||
|
||||
private bool _shouldRender;
|
||||
protected override bool ShouldRender() => _shouldRender;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await LoadModlist();
|
||||
_shouldRender = true;
|
||||
}
|
||||
|
||||
private async Task LoadModlist()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (ModlistPath == AbsolutePath.Empty) throw new FileNotFoundException("Modlist path was empty.");
|
||||
var modlist = await StandardInstaller.LoadFromFile(DTOs, ModlistPath);
|
||||
StateContainer.Modlist = modlist;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
toastService.ShowError("Could not load modlist!");
|
||||
Logger.LogError(e, "Exception loading Modlist file {Name}", ModlistPath);
|
||||
NavigationManager.NavigateTo(Select.Route);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var hex = (await ModlistPath.ToString().Hash()).ToHex();
|
||||
var prevSettings = await SettingsManager.Load<SavedInstallSettings>(InstallSettingsPrefix + hex);
|
||||
if (prevSettings.ModlistLocation == ModlistPath)
|
||||
{
|
||||
StateContainer.ModlistPath = prevSettings.ModlistLocation;
|
||||
StateContainer.InstallPath = prevSettings.InstallLocation;
|
||||
StateContainer.DownloadPath = prevSettings.DownloadLocation;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.LogWarning(e, "Exception loading previous settings for {Name}", ModlistPath);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var imageStream = await StandardInstaller.ModListImageStream(ModlistPath);
|
||||
var dotnetImageStream = new DotNetStreamReference(imageStream);
|
||||
StateContainer.ModlistImage = new string(await JSRuntime.InvokeAsync<string>("getBlobUrlFromStream", dotnetImageStream));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
toastService.ShowWarning("Could not load modlist image.");
|
||||
Logger.LogWarning(e, "Exception loading modlist image for {Name}", ModlistPath);
|
||||
}
|
||||
}
|
||||
|
||||
private async void SelectInstallFolder()
|
||||
{
|
||||
try
|
||||
{
|
||||
var installPath = await Dialog.ShowDialogNonBlocking(true);
|
||||
if (installPath is not null) StateContainer.InstallPath = (AbsolutePath) installPath;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.LogError(e, "Exception selecting install folder");
|
||||
}
|
||||
}
|
||||
|
||||
private async void SelectDownloadFolder()
|
||||
{
|
||||
try
|
||||
{
|
||||
var downloadPath = await Dialog.ShowDialogNonBlocking(true);
|
||||
if (downloadPath is not null) StateContainer.DownloadPath = (AbsolutePath) downloadPath;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.LogError(e, "Exception selecting download folder");
|
||||
}
|
||||
}
|
||||
|
||||
private void Install()
|
||||
{
|
||||
NavigationManager.NavigateTo(Installing.Route);
|
||||
}
|
||||
}
|
||||
|
||||
internal class SavedInstallSettings
|
||||
{
|
||||
public AbsolutePath ModlistLocation { get; set; } = AbsolutePath.Empty;
|
||||
public AbsolutePath InstallLocation { get; set; } = AbsolutePath.Empty;
|
||||
public AbsolutePath DownloadLocation { get; set; } = AbsolutePath.Empty;
|
||||
// public ModlistMetadata Metadata { get; set; }
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
@import "../Shared/Globals.scss";
|
||||
@import "../../Shared/Globals.scss";
|
||||
|
||||
$checkbox-background: rgba(255, 255, 255, 0.2);
|
||||
$checkbox-background-hover: darkgrey;
|
34
Wabbajack.App.Blazor/Pages/Install/Installing.razor
Normal file
34
Wabbajack.App.Blazor/Pages/Install/Installing.razor
Normal file
@ -0,0 +1,34 @@
|
||||
@page "/install/installing"
|
||||
|
||||
@namespace Wabbajack.App.Blazor.Pages
|
||||
|
||||
<div id="content">
|
||||
<div class="install-background">
|
||||
<img id="background-image" src="@ModlistImage" alt=""/>
|
||||
</div>
|
||||
<div class="list">
|
||||
@if (Modlist is not null)
|
||||
{
|
||||
<div class="left-side">
|
||||
<CascadingValue Value=this>
|
||||
<InfoBlock Supertitle="@StatusCategory" Title="@Modlist.Name"/>
|
||||
<StepLogger ShownSteps="3" Reverse="false" Steps="@StatusStep"/>
|
||||
</CascadingValue>
|
||||
</div>
|
||||
<div class="right-side">
|
||||
<InfoImage Image="@ModlistImage" Title="Some Mod Title" Subtitle="Author and others" Description="This mod adds something cool but I'm not going to tell you anything."/>
|
||||
<div id="progressthing1"></div>
|
||||
<div id="progressthing2"></div>
|
||||
<div id="progressthing3"></div>
|
||||
<div id="progressthing4"></div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
<div class="logger-container">
|
||||
<VirtualLogger/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@code {
|
||||
public const string Route = "/install/installing";
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Wabbajack.DTOs;
|
||||
@ -16,7 +17,7 @@ using Wabbajack.App.Blazor.State;
|
||||
|
||||
namespace Wabbajack.App.Blazor.Pages;
|
||||
|
||||
public partial class Configure
|
||||
public partial class Installing
|
||||
{
|
||||
[Inject] private ILogger<Configure> Logger { get; set; } = default!;
|
||||
[Inject] private IStateContainer StateContainer { get; set; } = default!;
|
||||
@ -26,14 +27,19 @@ public partial class Configure
|
||||
[Inject] private IGameLocator GameLocator { get; set; } = default!;
|
||||
[Inject] private SettingsManager SettingsManager { get; set; } = default!;
|
||||
[Inject] private IJSRuntime JSRuntime { get; set; } = default!;
|
||||
|
||||
|
||||
private ModList? Modlist => StateContainer.Modlist;
|
||||
|
||||
private string ModlistImage => StateContainer.ModlistImage;
|
||||
private AbsolutePath ModlistPath => StateContainer.ModlistPath;
|
||||
private AbsolutePath InstallPath { get; set; }
|
||||
private AbsolutePath DownloadPath { get; set; }
|
||||
private AbsolutePath InstallPath => StateContainer.InstallPath;
|
||||
private AbsolutePath DownloadPath => StateContainer.DownloadPath;
|
||||
|
||||
public string StatusCategory { get; set; }
|
||||
|
||||
private string LastStatus { get; set; }
|
||||
|
||||
public List<string> StatusStep { get; set; } = new();
|
||||
|
||||
private string StatusText { get; set; } = string.Empty;
|
||||
private InstallState InstallState => StateContainer.InstallState;
|
||||
|
||||
private const string InstallSettingsPrefix = "install-settings-";
|
||||
@ -41,69 +47,16 @@ public partial class Configure
|
||||
private bool _shouldRender;
|
||||
protected override bool ShouldRender() => _shouldRender;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
// var Location = KnownFolders.EntryPoint.Combine("downloaded_mod_lists", machineURL).WithExtension(Ext.Wabbajack);
|
||||
|
||||
await CheckValidInstallPath();
|
||||
Install();
|
||||
_shouldRender = true;
|
||||
}
|
||||
|
||||
private async Task CheckValidInstallPath()
|
||||
{
|
||||
if (ModlistPath == AbsolutePath.Empty) return;
|
||||
|
||||
var modlist = await StandardInstaller.LoadFromFile(DTOs, ModlistPath);
|
||||
StateContainer.Modlist = modlist;
|
||||
|
||||
var hex = (await ModlistPath.ToString().Hash()).ToHex();
|
||||
var prevSettings = await SettingsManager.Load<SavedInstallSettings>(InstallSettingsPrefix + hex);
|
||||
|
||||
if (prevSettings.ModlistLocation == ModlistPath)
|
||||
{
|
||||
StateContainer.ModlistPath = prevSettings.ModlistLocation;
|
||||
InstallPath = prevSettings.InstallLocation;
|
||||
DownloadPath = prevSettings.DownloadLocation;
|
||||
//ModlistMetadata = metadata ?? prevSettings.Metadata;
|
||||
}
|
||||
|
||||
// see https://docs.microsoft.com/en-us/aspnet/core/blazor/images?view=aspnetcore-6.0#streaming-examples
|
||||
var imageStream = await StandardInstaller.ModListImageStream(ModlistPath);
|
||||
var dotnetImageStream = new DotNetStreamReference(imageStream);
|
||||
// setImageUsingStreaming accepts the img id and the data stream
|
||||
await JSRuntime.InvokeVoidAsync("setImageUsingStreaming", "background-image", dotnetImageStream);
|
||||
}
|
||||
|
||||
private async void SelectInstallFolder()
|
||||
{
|
||||
try
|
||||
{
|
||||
var installPath = await Dialog.ShowDialogNonBlocking(true);
|
||||
if (installPath is not null) InstallPath = (AbsolutePath)installPath;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.LogError(e, "Exception selecting install folder");
|
||||
}
|
||||
}
|
||||
|
||||
private async void SelectDownloadFolder()
|
||||
{
|
||||
try
|
||||
{
|
||||
var downloadPath = await Dialog.ShowDialogNonBlocking(true);
|
||||
if (downloadPath is not null) DownloadPath = (AbsolutePath)downloadPath;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.LogError(e, "Exception selecting download folder");
|
||||
}
|
||||
}
|
||||
|
||||
private async Task Install()
|
||||
private async void Install()
|
||||
{
|
||||
if (Modlist is null) return;
|
||||
|
||||
|
||||
StateContainer.InstallState = InstallState.Installing;
|
||||
await Task.Run(() => BeginInstall(Modlist));
|
||||
}
|
||||
@ -130,12 +83,14 @@ public partial class Configure
|
||||
SystemParameters = ParametersConstructor.Create(),
|
||||
GameFolder = GameLocator.GameLocation(modlist.GameType)
|
||||
});
|
||||
|
||||
|
||||
installer.OnStatusUpdate = update =>
|
||||
{
|
||||
var (statusText, _, _) = update;
|
||||
if (StatusText == statusText) return;
|
||||
StatusText = statusText;
|
||||
if (LastStatus == update.StatusText) return;
|
||||
StatusStep.Insert(0, update.StatusText);
|
||||
StatusCategory = update.StatusCategory;
|
||||
LastStatus = update.StatusText;
|
||||
InvokeAsync(StateHasChanged);
|
||||
};
|
||||
|
||||
await installer.Begin(CancellationToken.None);
|
||||
@ -148,11 +103,3 @@ public partial class Configure
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class SavedInstallSettings
|
||||
{
|
||||
public AbsolutePath ModlistLocation { get; set; } = AbsolutePath.Empty;
|
||||
public AbsolutePath InstallLocation { get; set; } = AbsolutePath.Empty;
|
||||
public AbsolutePath DownloadLocation { get; set; } = AbsolutePath.Empty;
|
||||
// public ModlistMetadata Metadata { get; set; }
|
||||
}
|
115
Wabbajack.App.Blazor/Pages/Install/Installing.razor.scss
Normal file
115
Wabbajack.App.Blazor/Pages/Install/Installing.razor.scss
Normal file
@ -0,0 +1,115 @@
|
||||
@import "../../Shared/Globals.scss";
|
||||
|
||||
$checkbox-background: rgba(255, 255, 255, 0.2);
|
||||
$checkbox-background-hover: darkgrey;
|
||||
$checkbox-background-checked: $accent-color;
|
||||
$checkbox-size: 0.75rem;
|
||||
|
||||
@mixin path-span {
|
||||
display: block;
|
||||
height: 2rem;
|
||||
padding: 0.25rem;
|
||||
margin: 0.25rem;
|
||||
white-space: pre;
|
||||
cursor: pointer;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#content {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
align-content: center;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
color: white;
|
||||
flex-direction: column;
|
||||
|
||||
.install-background {
|
||||
position: absolute;
|
||||
width: calc(100% - #{$sidebar-width});
|
||||
height: calc(100% - #{$header-height});
|
||||
filter: blur(25px) brightness(50%);
|
||||
z-index: -1;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
}
|
||||
|
||||
.list {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
align-items: center;
|
||||
|
||||
.left-side, .right-side {
|
||||
flex: 1;
|
||||
margin: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.logger-container {
|
||||
height: 200px;
|
||||
width: 100%;
|
||||
padding: 0.5rem;
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
color: lightgrey;
|
||||
border: solid 1px black;
|
||||
}
|
||||
|
||||
.settings {
|
||||
font-size: 0.85rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
padding: 1rem;
|
||||
backdrop-filter: brightness(0.5);
|
||||
|
||||
.locations {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
|
||||
.labels {
|
||||
span {
|
||||
@include path-span;
|
||||
}
|
||||
}
|
||||
|
||||
.paths {
|
||||
flex: 1;
|
||||
margin-left: 1rem;
|
||||
overflow: hidden;
|
||||
|
||||
span {
|
||||
@include path-span;
|
||||
border: solid 1px rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.options {
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
flex-direction: column;
|
||||
margin-left: 2rem;
|
||||
}
|
||||
|
||||
.install {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin: 0.5rem;
|
||||
cursor: pointer;
|
||||
|
||||
img {
|
||||
width: 5rem;
|
||||
height: 5rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
@page "/install"
|
||||
@page "/install/select"
|
||||
|
||||
@namespace Wabbajack.App.Blazor.Pages
|
||||
|
||||
@ -26,5 +26,5 @@
|
||||
</div>
|
||||
|
||||
@code {
|
||||
public const string Route = "/install";
|
||||
public const string Route = "/install/select";
|
||||
}
|
@ -6,7 +6,7 @@ using Wabbajack.Paths;
|
||||
|
||||
namespace Wabbajack.App.Blazor.Pages;
|
||||
|
||||
public partial class Install
|
||||
public partial class Select
|
||||
{
|
||||
[Inject] private NavigationManager NavigationManager { get; set; } = default!;
|
||||
[Inject] private IStateContainer StateContainer { get; set; } = default!;
|
||||
@ -23,6 +23,4 @@ public partial class Install
|
||||
|
||||
NavigationManager.NavigateTo(Configure.Route);
|
||||
}
|
||||
|
||||
private void VerifyFile(AbsolutePath path) { }
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
<!DOCTYPE html>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
@ -41,6 +41,12 @@
|
||||
const blob = new Blob([arrayBuffer]);
|
||||
document.getElementById(imageElementId).src = URL.createObjectURL(blob);
|
||||
}
|
||||
|
||||
async function getBlobUrlFromStream(imageStream) {
|
||||
const arrayBuffer = await imageStream.arrayBuffer();
|
||||
const blob = new Blob([arrayBuffer]);
|
||||
return URL.createObjectURL(blob);
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
Loading…
Reference in New Issue
Block a user