mirror of
https://github.com/Maassoft/ColorControl.git
synced 2026-10-21 16:12:18 -05:00
fix some issues, add ddc settings, make new ui default
This commit is contained in:
1 parent
827157f30f
commit
1c22b2daf8
52 files changed
+5258
-3770
No files matched your search
+102
-27
@@ -1,43 +1,118 @@
|
||||
using ColorControl.Shared.Contracts;
|
||||
using ColorControl.UI.Services;
|
||||
using Microsoft.AspNetCore.Hosting.Server;
|
||||
using Microsoft.AspNetCore.Hosting.Server.Features;
|
||||
using System.Net;
|
||||
|
||||
namespace ColorControl.UI;
|
||||
|
||||
public static class Blazor
|
||||
{
|
||||
public static void Start(Config? config = null)
|
||||
{
|
||||
var builder = WebApplication.CreateBuilder();
|
||||
private static WebApplication? CurrentApplication;
|
||||
private static int Port;
|
||||
private static bool AllowRemoteConnections;
|
||||
|
||||
// Add services to the container.
|
||||
builder.Services.AddRazorComponents()
|
||||
.AddInteractiveServerComponents();
|
||||
public static bool IsRunning(Config config) => CurrentApplication != null && Port == config.UiPort && AllowRemoteConnections == config.UiAllowRemoteConnections;
|
||||
|
||||
builder.Services.AddSingleton<AppState>(new AppState { SelectedTheme = (config?.UseDarkMode ?? true) ? "dark" : "light" });
|
||||
builder.Services.AddTransient<RpcUiClientService>();
|
||||
builder.Services.AddTransient<JSHelper>();
|
||||
builder.Services.AddHttpContextAccessor();
|
||||
builder.Services.AddSingleton<NotificationService>();
|
||||
builder.WebHost.ConfigureKestrel(o => o.ListenAnyIP(config?.UiPort > 0 ? config.UiPort : 5000));
|
||||
public static async Task Start(Config config)
|
||||
{
|
||||
if (IsRunning(config))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var app = builder.Build();
|
||||
await Stop();
|
||||
|
||||
// Configure the HTTP request pipeline.
|
||||
if (!app.Environment.IsDevelopment())
|
||||
{
|
||||
app.UseExceptionHandler("/Error", createScopeForErrors: true);
|
||||
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
|
||||
app.UseHsts();
|
||||
}
|
||||
var builder = WebApplication.CreateBuilder();
|
||||
|
||||
app.UseHttpsRedirection();
|
||||
// Add services to the container.
|
||||
builder.Services.AddRazorComponents()
|
||||
.AddInteractiveServerComponents();
|
||||
|
||||
app.UseStaticFiles();
|
||||
app.UseAntiforgery();
|
||||
builder.Services.AddSingleton<AppState>(new AppState { SelectedTheme = config.UseDarkMode ? "dark" : "light" });
|
||||
builder.Services.AddTransient<RpcUiClientService>();
|
||||
builder.Services.AddTransient<JSHelper>();
|
||||
builder.Services.AddHttpContextAccessor();
|
||||
builder.Services.AddSingleton<NotificationService>();
|
||||
|
||||
app.MapRazorComponents<Components.App>()
|
||||
.AddInteractiveServerRenderMode();
|
||||
builder.Services.Configure<HostOptions>(opts => opts.ShutdownTimeout = TimeSpan.FromSeconds(3));
|
||||
|
||||
var listenPort = config.UiPort > 0 ? config.UiPort : 0;
|
||||
|
||||
builder.WebHost.ConfigureKestrel(options =>
|
||||
{
|
||||
if (config.UiAllowRemoteConnections)
|
||||
{
|
||||
options.ListenAnyIP(listenPort);
|
||||
}
|
||||
else
|
||||
{
|
||||
options.Listen(IPAddress.Parse("127.0.0.1"), listenPort);
|
||||
}
|
||||
});
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
// Configure the HTTP request pipeline.
|
||||
if (!app.Environment.IsDevelopment())
|
||||
{
|
||||
app.UseExceptionHandler("/Error", createScopeForErrors: true);
|
||||
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
|
||||
app.UseHsts();
|
||||
}
|
||||
|
||||
app.UseHttpsRedirection();
|
||||
|
||||
app.UseStaticFiles();
|
||||
app.UseAntiforgery();
|
||||
|
||||
app.MapRazorComponents<Components.App>()
|
||||
.AddInteractiveServerRenderMode();
|
||||
|
||||
CurrentApplication = app;
|
||||
Port = config.UiPort;
|
||||
AllowRemoteConnections = config.UiAllowRemoteConnections;
|
||||
|
||||
await app.RunAsync();
|
||||
}
|
||||
|
||||
public static async Task Stop()
|
||||
{
|
||||
if (CurrentApplication != null)
|
||||
{
|
||||
await CurrentApplication.StopAsync();
|
||||
CurrentApplication = null;
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetCurrentUrl()
|
||||
{
|
||||
var port = GetCurrentPort();
|
||||
|
||||
return $"http://localhost:{port}";
|
||||
}
|
||||
|
||||
public static int GetCurrentPort()
|
||||
{
|
||||
if (CurrentApplication == null)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
var server = CurrentApplication.Services.GetService<IServer>();
|
||||
var addressFeature = server?.Features.Get<IServerAddressesFeature>();
|
||||
|
||||
if (addressFeature == null)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
foreach (var address in addressFeature.Addresses)
|
||||
{
|
||||
return int.Parse(address.Split(':').Last());
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
app.Run();
|
||||
}
|
||||
}
|
||||
@@ -51,6 +51,16 @@
|
||||
<label class="form-label" for="description">Description</label>
|
||||
<input class="form-control" type="text" id="description" @bind="ColorProfile.Description" />
|
||||
</div>
|
||||
<div class="mb-2">
|
||||
<label class="form-label" for="renderingIntent">Rendering intent</label>
|
||||
<select class="form-select" id="renderingIntent" @bind="ColorProfile.RenderingIntent">
|
||||
@foreach (var renderingIntent in Enum.GetValues<LittleCms.RenderingIntent>().Where(ri => ri <= LittleCms.RenderingIntent.ABSOLUTE_COLORIMETRIC))
|
||||
{
|
||||
<option value="@renderingIntent">@renderingIntent.GetDescription()</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="accordion accordion-flush" id="presetAccordion">
|
||||
|
||||
<div class="accordion-item">
|
||||
@@ -236,21 +246,49 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="mb-2">
|
||||
<label class="form-label" for="brightnessBoost">Brightness boost (%)</label>
|
||||
<input class="form-control" id="brightnessBoost" type="number" min="-100" max="100" @bind="ColorProfile.SDRBrightnessBoost" disabled="@(ColorProfile.SDRTransferFunction == SDRTransferFunction.ToneMappedPiecewise)" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="mb-2">
|
||||
<label class="form-label" for="shadowDetailBoost">Shadow detail boost (%)</label>
|
||||
<input class="form-control" id="shadowDetailBoost" type="number" min="0" max="100" @bind="ColorProfile.ShadowDetailBoost" disabled="@(ColorProfile.SDRTransferFunction == SDRTransferFunction.Piecewise || ColorProfile.SDRTransferFunction == SDRTransferFunction.ToneMappedPiecewise)" />
|
||||
</div>
|
||||
}
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="mb-2">
|
||||
<label class="form-label" for="brightnessBoost">Brightness boost (%)</label>
|
||||
<input class="form-control" id="brightnessBoost" type="number" min="-100" max="100" @bind="ColorProfile.SDRBrightnessBoost" disabled="@(ColorProfile.SDRTransferFunction == SDRTransferFunction.ToneMappedPiecewise)" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col">
|
||||
<div class="mb-2">
|
||||
<label class="form-label" for="shadowDetailBoost">Shadow detail boost (%)</label>
|
||||
<input class="form-control" id="shadowDetailBoost" type="number" min="-50" max="200" @bind="ColorProfile.ShadowDetailBoost" disabled="@(ColorProfile.SDRTransferFunction == SDRTransferFunction.ToneMappedPiecewise)" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="mb-2">
|
||||
<label class="form-label" for="shadowDetailRange">Shadow detail range (%)</label>
|
||||
<input class="form-control" id="shadowDetailRange" type="number" min="0" max="100" @bind="ColorProfile.ShadowDetailRange" disabled="@(ColorProfile.SDRTransferFunction == SDRTransferFunction.ToneMappedPiecewise)" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="mb-2">
|
||||
<label class="form-label" for="redGain">Red gain (%)</label>
|
||||
<input class="form-control" id="redGain" type="number" min="1" max="200" step="0.01" @bind="ColorProfile.RedGain" disabled="@(ColorProfile.SDRTransferFunction == SDRTransferFunction.ToneMappedPiecewise)" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="mb-2">
|
||||
<label class="form-label" for="greenGain">Green gain (%)</label>
|
||||
<input class="form-control" id="greenGain" type="number" min="1" max="200" step="0.01" @bind="ColorProfile.GreenGain" disabled="@(ColorProfile.SDRTransferFunction == SDRTransferFunction.ToneMappedPiecewise)" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="mb-2">
|
||||
<label class="form-label" for="blueGain">Blue gain (%)</label>
|
||||
<input class="form-control" id="blueGain" type="number" min="1" max="200" step="0.01" @bind="ColorProfile.BlueGain" disabled="@(ColorProfile.SDRTransferFunction == SDRTransferFunction.ToneMappedPiecewise)" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@if (ColorProfile.IsHDRProfile)
|
||||
{
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="mb-2">
|
||||
@@ -280,17 +318,6 @@
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="mb-2">
|
||||
<label class="form-label" for="shadowDetailBoost">Shadow detail boost (%)</label>
|
||||
<input class="form-control" id="shadowDetailBoost" type="number" min="0" max="100" @bind="ColorProfile.ShadowDetailBoost" disabled="@(ColorProfile.SDRTransferFunction == SDRTransferFunction.Piecewise)" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -68,6 +68,10 @@ else
|
||||
{
|
||||
<span class="ms-2 badge text-bg-warning" title="Show in Quick Access">QA</span>
|
||||
}
|
||||
@if (!preset.PathExists)
|
||||
{
|
||||
<span class="ms-2 badge text-bg-danger" title="@($"Path '{preset.Path}' is not found")">Not found</span>
|
||||
}
|
||||
</h5>
|
||||
</div>
|
||||
<span class="d-none d-lg-block">
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
|
||||
<div class="mb-2">
|
||||
<label class="form-label" for="@fieldId">@field.Label</label>
|
||||
<select class="form-select" id="@fieldId" @bind="field.StringValue">
|
||||
<select class="form-select" id="@fieldId" @bind="field.StringValue" @bind:after="() => FieldBindAfter(field)">
|
||||
@if (field.ValueType != null)
|
||||
{
|
||||
@foreach (var item in Enum.GetValues(field.ValueType))
|
||||
@@ -111,4 +111,12 @@
|
||||
@code {
|
||||
[Parameter]
|
||||
public List<FieldDefinition>? Fields { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public EventCallback<FieldDefinition> FieldValueChanged { get; set; }
|
||||
|
||||
private async Task FieldBindAfter(FieldDefinition field)
|
||||
{
|
||||
await FieldValueChanged.InvokeAsync(field);
|
||||
}
|
||||
}
|
||||
@@ -112,5 +112,4 @@
|
||||
|
||||
ExtraLabelStyling = LabelStylingFunc?.Invoke(Value);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -19,89 +19,170 @@
|
||||
<div class="d-flex ms-auto">
|
||||
@if (NvPresets != null || SamsungPresets != null || LgPresets != null || CustomItems != null)
|
||||
{
|
||||
<div class="dropdown dropend mb-1">
|
||||
<div class="dropdown dropstart mb-1">
|
||||
<button type="button" class="btn btn-primary btn-sm dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false" data-bs-auto-close="outside">Add</button>
|
||||
<form class="dropdown-menu p-4 dropdown-menu-end" style="width: 360px">
|
||||
@if (NvPresets != null && NvPresetsEnabled)
|
||||
{
|
||||
<div class="mb-2">
|
||||
<label class="form-label" for="nvPreset">NVIDIA preset</label>
|
||||
<select class="form-select" multiple id="nvPreset" @onchange="NvPresetChange">
|
||||
@foreach (var preset in NvPresets)
|
||||
{
|
||||
<option value="@preset.id">@preset.IdOrName</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
}
|
||||
@if (SamsungPresets != null && SamsungPresetsEnabled)
|
||||
{
|
||||
<div class="mb-2">
|
||||
<label class="form-label" for="samsungPreset">Samsung preset</label>
|
||||
<select class="form-select" id="samsungPreset" @bind="SamsungPresetToAddId">
|
||||
<option value="">Select preset</option>
|
||||
@foreach (var preset in SamsungPresets)
|
||||
{
|
||||
<option value="@preset.id">@preset.IdOrName</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
}
|
||||
@if (LgPresets != null && LgPresetsEnabled)
|
||||
{
|
||||
<div class="mb-2">
|
||||
<label class="form-label" for="lgPreset">LG preset</label>
|
||||
<select class="form-select" id="lgPreset" @bind="LgPresetToAddId">
|
||||
<option value="">Select preset</option>
|
||||
@foreach (var preset in LgPresets)
|
||||
{
|
||||
<option value="@preset.id">@preset.IdOrName</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
}
|
||||
@if (CustomItems != null)
|
||||
{
|
||||
foreach (var customItem in CustomItems)
|
||||
{
|
||||
<div class="mb-2">
|
||||
<label class="form-label" for="customItem">@customItem.Name</label>
|
||||
<select class="form-select" id="customItem" @bind="customItem.SelectedItem">
|
||||
<option value="">Select item</option>
|
||||
@foreach (var item in customItem.Items)
|
||||
{
|
||||
<option value="@item">@item</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
<form class="dropdown-menu p-3 dropdown-menu-end" style="width: 21rem; height: 430px">
|
||||
<ul class="nav nav-tabs" id="presetTab" role="tablist">
|
||||
@{
|
||||
var linkActive = "active";
|
||||
}
|
||||
}
|
||||
|
||||
<StartProgramInput @bind-Path="StartProgramPath" @bind-Parameters="StartProgramParameters"></StartProgramInput>
|
||||
|
||||
@if (ActionItems != null)
|
||||
{
|
||||
foreach (var customItem in ActionItems)
|
||||
@if (NvPresets != null && NvPresetsEnabled)
|
||||
{
|
||||
<div class="mb-2">
|
||||
<label class="form-label" for="advancedCustomItem">@customItem.Name</label>
|
||||
<select class="form-select" id="advancedCustomItem" @bind="customItem.SelectedActionName" @bind:after="() => AdvancedItemChanged(customItem)">
|
||||
<option value="">Select action</option>
|
||||
@foreach (var keyValue in customItem.GroupedActions)
|
||||
{
|
||||
<optgroup label="@keyValue.Key">
|
||||
@foreach (var item in keyValue.Value)
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link px-2 @(linkActive)" id="nvidia-tab" data-bs-toggle="tab" data-bs-target="#nvidia-tab-pane" type="button" role="tab" aria-controls="nvidia-tab-pane" aria-selected="true">NVIDIA</button>
|
||||
</li>
|
||||
linkActive = "";
|
||||
}
|
||||
@if (SamsungPresets != null && SamsungPresetsEnabled)
|
||||
{
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link px-2 @(linkActive)" id="samsung-tab" data-bs-toggle="tab" data-bs-target="#samsung-tab-pane" type="button" role="tab" aria-controls="samsung-tab-pane" aria-selected="true">Samsung</button>
|
||||
</li>
|
||||
linkActive = "";
|
||||
}
|
||||
@if (LgPresets != null && LgPresetsEnabled)
|
||||
{
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link px-2 @(linkActive)" id="lg-tab" data-bs-toggle="tab" data-bs-target="#lg-tab-pane" type="button" role="tab" aria-controls="lg-tab-pane" aria-selected="true">LG</button>
|
||||
</li>
|
||||
linkActive = "";
|
||||
}
|
||||
@if (CustomItems != null)
|
||||
{
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link px-2 @(linkActive)" id="custom-tab" data-bs-toggle="tab" data-bs-target="#custom-tab-pane" type="button" role="tab" aria-controls="custom-tab-pane" aria-selected="true">Custom</button>
|
||||
</li>
|
||||
linkActive = "";
|
||||
}
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link px-2 @(linkActive)" id="program-tab" data-bs-toggle="tab" data-bs-target="#program-tab-pane" type="button" role="tab" aria-controls="program-tab-pane" aria-selected="true">Program</button>
|
||||
</li>
|
||||
@if (ActionItems != null)
|
||||
{
|
||||
linkActive = "";
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link px-2 @(linkActive)" id="action-tab" data-bs-toggle="tab" data-bs-target="#action-tab-pane" type="button" role="tab" aria-controls="action-tab-pane" aria-selected="true">Action</button>
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
|
||||
<div class="tab-content" id="presetTabContent">
|
||||
@{
|
||||
var tabActive = "show active";
|
||||
}
|
||||
|
||||
@if (NvPresets != null && NvPresetsEnabled)
|
||||
{
|
||||
<div class="tab-pane fade @(tabActive)" id="nvidia-tab-pane" role="tabpanel" aria-labelledby="nvidia-tab">
|
||||
<div class="mt-3 mb-3">
|
||||
<label class="form-label" for="nvPreset">NVIDIA preset</label>
|
||||
<select class="form-select" multiple id="nvPreset" @onchange="NvPresetChange" style="height: 250px">
|
||||
@foreach (var preset in NvPresets)
|
||||
{
|
||||
<option value="@preset.id">@preset.IdOrName</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
<button type="button" class="btn btn-sm btn-primary" @onclick="() => AddNvPresetOnClick()" disabled="@(NvPresetsToAdd.Count == 0)">Add item(s)</button>
|
||||
</div>
|
||||
tabActive = "";
|
||||
}
|
||||
@if (SamsungPresets != null && SamsungPresetsEnabled)
|
||||
{
|
||||
<div class="tab-pane fade @(tabActive)" id="samsung-tab-pane" role="tabpanel" aria-labelledby="samsung-tab">
|
||||
<div class="mt-3 mb-3">
|
||||
<label class="form-label" for="samsungPreset">Samsung preset</label>
|
||||
<select class="form-select" id="samsungPreset" @bind="SamsungPresetToAddId">
|
||||
<option value="">Select preset</option>
|
||||
@foreach (var preset in SamsungPresets)
|
||||
{
|
||||
<option value="@preset.id">@preset.IdOrName</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
<button type="button" class="btn btn-sm btn-primary" @onclick="() => AddSamsungPresetOnClick()">Add item</button>
|
||||
</div>
|
||||
tabActive = "";
|
||||
}
|
||||
@if (LgPresets != null && LgPresetsEnabled)
|
||||
{
|
||||
<div class="tab-pane fade @(tabActive)" id="lg-tab-pane" role="tabpanel" aria-labelledby="lg-tab">
|
||||
<div class="mt-3 mb-3">
|
||||
<label class="form-label" for="lgPreset">LG preset</label>
|
||||
<select class="form-select" id="lgPreset" @bind="LgPresetToAddId">
|
||||
<option value="">Select preset</option>
|
||||
@foreach (var preset in LgPresets)
|
||||
{
|
||||
<option value="@preset.id">@preset.IdOrName</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
<button type="button" class="btn btn-sm btn-primary" @onclick="() => AddLgPresetOnClick()">Add item</button>
|
||||
</div>
|
||||
tabActive = "";
|
||||
}
|
||||
@if (CustomItems != null)
|
||||
{
|
||||
<div class="tab-pane fade @(tabActive)" id="custom-tab-pane" role="tabpanel" aria-labelledby="custom-tab">
|
||||
@foreach (var customItem in CustomItems)
|
||||
{
|
||||
<div class="mt-3 mb-3">
|
||||
<label class="form-label" for="customItem">@customItem.Name</label>
|
||||
<select class="form-select" id="customItem" @bind="customItem.SelectedItem">
|
||||
<option value="">Select item</option>
|
||||
@foreach (var item in customItem.Items)
|
||||
{
|
||||
<option value="@item.Name">@item.Title</option>
|
||||
<option value="@item">@item</option>
|
||||
}
|
||||
</optgroup>
|
||||
}
|
||||
</select>
|
||||
</select>
|
||||
</div>
|
||||
}
|
||||
<button type="button" class="btn btn-sm btn-primary" @onclick="() => AddCustomItemsOnClick()">Add item</button>
|
||||
</div>
|
||||
<FieldDefs Fields="ActionFields"></FieldDefs>
|
||||
tabActive = "";
|
||||
}
|
||||
}
|
||||
<button type="button" class="btn btn-sm btn-primary" @onclick="() => AddPresetOnClick()">Add items</button>
|
||||
|
||||
<div class="tab-pane fade @(tabActive)" id="program-tab-pane" role="tabpanel" aria-labelledby="program-tab">
|
||||
<div class="mt-3 mb-3">
|
||||
<StartProgramInput @bind-Path="StartProgramPath" @bind-Parameters="StartProgramParameters"></StartProgramInput>
|
||||
</div>
|
||||
<button type="button" class="btn btn-sm btn-primary" @onclick="() => AddStartProgramOnClick()">Add item</button>
|
||||
</div>
|
||||
|
||||
@{
|
||||
tabActive = "";
|
||||
}
|
||||
|
||||
@if (ActionItems != null)
|
||||
{
|
||||
<div class="tab-pane fade @(tabActive)" id="action-tab-pane" role="tabpanel" aria-labelledby="action-tab">
|
||||
<div class="mt-3 mb-3">
|
||||
@foreach (var customItem in ActionItems)
|
||||
{
|
||||
<div class="mb-2">
|
||||
<label class="form-label" for="advancedCustomItem">@customItem.Name</label>
|
||||
<select class="form-select" id="advancedCustomItem" @bind="customItem.SelectedActionName" @bind:after="() => AdvancedItemChanged(customItem)">
|
||||
<option value="">Select action</option>
|
||||
@foreach (var keyValue in customItem.GroupedActions)
|
||||
{
|
||||
<optgroup label="@keyValue.Key">
|
||||
@foreach (var item in keyValue.Value)
|
||||
{
|
||||
<option value="@item.Name">@item.Title</option>
|
||||
}
|
||||
</optgroup>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
<FieldDefs Fields="ActionFields"></FieldDefs>
|
||||
}
|
||||
</div>
|
||||
<button type="button" class="btn btn-sm btn-primary" @onclick="() => AddActionItemsOnClick()">Add item</button>
|
||||
</div>
|
||||
}
|
||||
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
}
|
||||
@@ -121,7 +202,7 @@
|
||||
{
|
||||
var stepIndex = index;
|
||||
|
||||
<button type="button" class="btn btn-outline-primary dropdown-toggle text-break text-wrap" data-bs-toggle="dropdown" aria-expanded="false" data-bs-auto-close="outside">@step.Raw</button>
|
||||
<button type="button" class="btn btn-outline-primary dropdown-toggle text-break text-wrap" data-bs-toggle="dropdown" aria-expanded="false" data-bs-auto-close="outside" @onclick="() => PresetStepClick(step)">@step.Raw</button>
|
||||
<form class="dropdown-menu p-4 dropdown-menu-end" style="width: 200px">
|
||||
<div class="mb-2">
|
||||
<button type="button" class="btn btn-primary btn-sm" data-bs-dismiss="dropdown" title="Move left" disabled="@(stepIndex == 0)" @onclick="() => MoveLeftOnClick(stepIndex)"><</button>
|
||||
@@ -129,6 +210,10 @@
|
||||
<button type="button" class="btn btn-primary btn-sm" data-bs-dismiss="dropdown" @onclick="() => RemoveOnClick(stepIndex)">Remove</button>
|
||||
</div>
|
||||
<RangeInput TValue="int" @bind-Value="step.Delay" Id="delay" Label="Delay" Unit="ms" Max="10000" @bind-Value:after="() => AfterDelayChanged()" />
|
||||
@if (ActionFieldsEdit != null)
|
||||
{
|
||||
<FieldDefs Fields="ActionFieldsEdit" FieldValueChanged="ActionFieldValueChanged"></FieldDefs>
|
||||
}
|
||||
</form>
|
||||
|
||||
index++;
|
||||
@@ -167,6 +252,8 @@
|
||||
[Parameter]
|
||||
public bool LgPresetsEnabled { get; set; } = true;
|
||||
|
||||
private PresetStep? CurrentPresetStep;
|
||||
|
||||
public class ActionStepItem
|
||||
{
|
||||
public string Name { get; private set; }
|
||||
@@ -219,6 +306,7 @@
|
||||
private string? RawText;
|
||||
|
||||
private List<FieldDefinition>? ActionFields;
|
||||
private List<FieldDefinition>? ActionFieldsEdit;
|
||||
|
||||
private string? StartProgramPath;
|
||||
private string? StartProgramParameters;
|
||||
@@ -229,9 +317,16 @@
|
||||
{
|
||||
if (Steps != null)
|
||||
{
|
||||
var stepIndex = CurrentPresetStep != null ? PresetSteps.IndexOf(CurrentPresetStep) : -1;
|
||||
|
||||
PresetSteps.Clear();
|
||||
PresetSteps.AddRange(Steps.Select(s => PresetStep.Parse(s)));
|
||||
RawText = string.Join(", ", PresetSteps);
|
||||
|
||||
if (stepIndex > -1 && stepIndex < PresetSteps.Count)
|
||||
{
|
||||
CurrentPresetStep = PresetSteps[stepIndex];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -296,6 +391,72 @@
|
||||
await EmitSteps();
|
||||
}
|
||||
|
||||
private async Task AddNvPresetOnClick()
|
||||
{
|
||||
NvPresetsToAdd.ForEach(id => AddPreset(NvPresets, "NvPreset", id));
|
||||
|
||||
await EmitSteps();
|
||||
}
|
||||
|
||||
private async Task AddSamsungPresetOnClick()
|
||||
{
|
||||
AddPreset(SamsungPresets, "SamsungPreset", SamsungPresetToAddId);
|
||||
|
||||
await EmitSteps();
|
||||
}
|
||||
|
||||
private async Task AddLgPresetOnClick()
|
||||
{
|
||||
AddPreset(LgPresets, "LgPreset", LgPresetToAddId);
|
||||
|
||||
await EmitSteps();
|
||||
}
|
||||
|
||||
private async Task AddCustomItemsOnClick()
|
||||
{
|
||||
if (CustomItems != null && Steps != null)
|
||||
{
|
||||
foreach (var customItem in CustomItems)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(customItem.SelectedItem))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
PresetSteps.Add(PresetStep.Parse(customItem.SelectedItem));
|
||||
}
|
||||
}
|
||||
|
||||
await EmitSteps();
|
||||
}
|
||||
|
||||
private async Task AddActionItemsOnClick()
|
||||
{
|
||||
if (ActionItems != null && Steps != null)
|
||||
{
|
||||
foreach (var customItem in ActionItems)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(customItem.SelectedActionName))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var stepString = customItem.GetStepString(ActionFields);
|
||||
|
||||
PresetSteps.Add(PresetStep.Parse(stepString));
|
||||
}
|
||||
}
|
||||
|
||||
await EmitSteps();
|
||||
}
|
||||
|
||||
private async Task AddStartProgramOnClick()
|
||||
{
|
||||
AddStartProgram();
|
||||
|
||||
await EmitSteps();
|
||||
}
|
||||
|
||||
private async Task AddPresetOnClick()
|
||||
{
|
||||
NvPresetsToAdd.ForEach(id => AddPreset(NvPresets, "NvPreset", id));
|
||||
@@ -457,4 +618,34 @@
|
||||
NvPresetsToAdd.AddRange(items.Select(i => int.Parse(i)));
|
||||
}
|
||||
}
|
||||
|
||||
private void PresetStepClick(PresetStep step)
|
||||
{
|
||||
CurrentPresetStep = step;
|
||||
|
||||
var action = ActionItems?.SelectMany(ai => ai.Actions).FirstOrDefault(a => a.Name.Equals(step.ActionName, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
if (action == null)
|
||||
{
|
||||
ActionFieldsEdit = null;
|
||||
return;
|
||||
}
|
||||
|
||||
var field = CreateField(action);
|
||||
field.StringValue = step.ActionValue;
|
||||
|
||||
ActionFieldsEdit = [field];
|
||||
}
|
||||
|
||||
private async Task ActionFieldValueChanged(FieldDefinition field)
|
||||
{
|
||||
if (CurrentPresetStep == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
CurrentPresetStep.ActionValue = field.StringValue;
|
||||
|
||||
await EmitSteps();
|
||||
}
|
||||
}
|
||||
@@ -524,6 +524,86 @@
|
||||
</div>
|
||||
}
|
||||
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header">
|
||||
<span class="d-flex align-items-baseline">
|
||||
@if (!Preset.IsDisplayPreset)
|
||||
{
|
||||
<input class="form-check-input me-1" style="font-size: 1rem" title="Apply these settings" type="checkbox" @bind="Preset.DdcSettings.ApplyDdc" id="applyDdc">
|
||||
}
|
||||
<button class="accordion-button collapsed py-2 @(Preset.DdcSettings.ApplyDdc ? "text-warning fw-bold" : "")" type="button" data-bs-toggle="collapse" data-bs-target="#ddcSettings">
|
||||
DDC settings
|
||||
</button>
|
||||
</span>
|
||||
</h2>
|
||||
<div id="ddcSettings" class="accordion-collapse collapse" data-bs-parent="#presetAccordion">
|
||||
<div class="accordion-body">
|
||||
|
||||
@if (!Preset.DdcSettings.Settings.Any())
|
||||
{
|
||||
<div>
|
||||
<label class="form-label">No settings found. Click to add:</label>
|
||||
<button class="btn btn-primary btn-sm" type="button" @onclick="() => Preset.DdcSettings.Settings.Add(new DdcSetting())">Add</button>
|
||||
</div>
|
||||
}
|
||||
|
||||
@foreach (var ddcSetting in Preset.DdcSettings.Settings)
|
||||
{
|
||||
<div class="mb-2">
|
||||
<label class="form-label" for="vcpCode">VCP code</label>
|
||||
<select class="form-select" id="vcpCode" @bind="ddcSetting.VcpHexCode" @bind:after="() => AfterVcpChanged(ddcSetting)">
|
||||
<option value="">Not selected</option>
|
||||
@foreach (var vcpCodeKeyValue in VcpCodes.CodeList)
|
||||
{
|
||||
<option value="@vcpCodeKeyValue.Key">@($"{vcpCodeKeyValue.Key}: {(string.IsNullOrEmpty(vcpCodeKeyValue.Value) ? "Unknown" : vcpCodeKeyValue.Value)}")</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="mb-2">
|
||||
<label class="form-label" for="ddcValue">Value</label>
|
||||
<input class="form-control" type="number" @bind="ddcSetting.Value" id="ddcValue">
|
||||
@if (ddcSetting.MaxValue != 0)
|
||||
{
|
||||
<div id="ddcValue_help" class="form-text">
|
||||
Max. value: @ddcSetting.MaxValue
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
@if (!Preset.IsDisplayPreset)
|
||||
{
|
||||
<div class="mb-2">
|
||||
<label class="form-label" for="ddcValueChangeType">Value change type</label>
|
||||
<select class="form-select" id="ddcValueChangeType" @bind="ddcSetting.ValueChangeType">
|
||||
@foreach (var changeType in Enum.GetValues<DdcSetting.ValueChangeTypes>())
|
||||
{
|
||||
<option value="@changeType">@changeType.GetDescription()</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
@if (!string.IsNullOrEmpty(DdcErrorMessage))
|
||||
{
|
||||
<div class="alert alert-danger align-items-center" role="alert">
|
||||
<div>
|
||||
@DdcErrorMessage
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
<div class="mb-2">
|
||||
<input class="form-check-input" type="checkbox" @bind="Preset.DdcSettings.RemoveOutOfRangeOsd" id="ddcRemoveOsd">
|
||||
<label class="form-check-label" for="ddcRemoveOsd">
|
||||
Try to remove "Out of range" OSD
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if (ShowOverclocking)
|
||||
{
|
||||
<div class="accordion-item">
|
||||
@@ -560,39 +640,40 @@
|
||||
</div>
|
||||
}
|
||||
|
||||
<div class="accordion accordion-flush" id="presetAccordion">
|
||||
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header">
|
||||
<button class="accordion-button collapsed py-2" type="button" data-bs-toggle="collapse" data-bs-target="#advancedSettings">
|
||||
Triggers
|
||||
</button>
|
||||
</h2>
|
||||
<div id="advancedSettings" class="accordion-collapse collapse" data-bs-parent="#presetAccordion">
|
||||
<div class="accordion-body">
|
||||
<TriggerInput Triggers="Preset.Triggers"></TriggerInput>
|
||||
@if (!Preset.IsDisplayPreset)
|
||||
{
|
||||
<div class="accordion accordion-flush" id="presetAccordion">
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header">
|
||||
<button class="accordion-button collapsed py-2" type="button" data-bs-toggle="collapse" data-bs-target="#advancedSettings">
|
||||
Triggers
|
||||
</button>
|
||||
</h2>
|
||||
<div id="advancedSettings" class="accordion-collapse collapse" data-bs-parent="#presetAccordion">
|
||||
<div class="accordion-body">
|
||||
<TriggerInput Triggers="Preset.Triggers"></TriggerInput>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header">
|
||||
<button class="accordion-button collapsed py-2" type="button" data-bs-toggle="collapse" data-bs-target="#steps">
|
||||
Steps
|
||||
</button>
|
||||
</h2>
|
||||
<div id="steps" class="accordion-collapse collapse" data-bs-parent="#presetAccordion">
|
||||
<div class="accordion-body">
|
||||
<StepsInput Label="Steps" @bind-Steps="Preset.Steps" NvPresetsEnabled="false" TPreset="NvPreset"></StepsInput>
|
||||
<div class="mb-2">
|
||||
<label class="form-label" for="description">Description</label>
|
||||
<textarea class="form-control" id="description" type="text" @bind="Preset.Description" />
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header">
|
||||
<button class="accordion-button collapsed py-2" type="button" data-bs-toggle="collapse" data-bs-target="#steps">
|
||||
Steps
|
||||
</button>
|
||||
</h2>
|
||||
<div id="steps" class="accordion-collapse collapse" data-bs-parent="#presetAccordion">
|
||||
<div class="accordion-body">
|
||||
<StepsInput Label="Steps" @bind-Steps="Preset.Steps" NvPresetsEnabled="false" TPreset="NvPreset"></StepsInput>
|
||||
<div class="mb-2">
|
||||
<label class="form-label" for="description">Description</label>
|
||||
<textarea class="form-control" id="description" type="text" @bind="Preset.Description" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
}
|
||||
|
||||
</div>
|
||||
}
|
||||
@@ -647,6 +728,8 @@
|
||||
private NvPreset? OriginalPreset;
|
||||
private bool Applying;
|
||||
private bool Queued;
|
||||
private bool SkipNextApply;
|
||||
private string? DdcErrorMessage;
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
@@ -674,6 +757,11 @@
|
||||
{
|
||||
resolutions = await _rpcClientService.CallAsync<List<VirtualResolution>>("NvService", "GetAvailableResolutionsV2", Preset);
|
||||
refreshRates = await _rpcClientService.CallAsync<List<Rational>>("NvService", "GetAvailableRefreshRatesV2", Preset);
|
||||
|
||||
if (Preset.IsDisplayPreset && !Preset.DdcSettings.Settings.Any())
|
||||
{
|
||||
Preset.DdcSettings.Settings.Add(new DdcSetting());
|
||||
}
|
||||
}
|
||||
selectedActiveResolution = Preset?.DisplayConfig.Resolution?.GetActiveString();
|
||||
selectedVirtualResolution = Preset?.DisplayConfig.Resolution?.GetVirtualString();
|
||||
@@ -698,6 +786,12 @@
|
||||
|
||||
private async Task DoApplyImmediately()
|
||||
{
|
||||
if (SkipNextApply)
|
||||
{
|
||||
SkipNextApply = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsVisible && OriginalPreset != null && Preset?.IsDisplayPreset == true)
|
||||
{
|
||||
if (Applying)
|
||||
@@ -722,7 +816,7 @@
|
||||
|
||||
Applying = false;
|
||||
}
|
||||
while (Queued);
|
||||
while (Queued && !SkipNextApply);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -743,9 +837,18 @@
|
||||
|
||||
if (Preset.IsDisplayPreset)
|
||||
{
|
||||
Preset.UpdateAutoApplySettings(PresetParam);
|
||||
|
||||
await ApplyDisplayPreset();
|
||||
if (OriginalPreset != null)
|
||||
{
|
||||
Preset.UpdateAutoApplySettings(OriginalPreset, true);
|
||||
}
|
||||
|
||||
if (Preset.HasApplicableSettings)
|
||||
{
|
||||
Preset.UpdateAutoApplySettings(PresetParam);
|
||||
|
||||
await ApplyDisplayPreset();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -768,7 +871,7 @@
|
||||
|
||||
private async Task ApplyDisplayPreset()
|
||||
{
|
||||
var result = await _rpcClientService.CallAsync<bool>("NvService", "ApplyPreset", Preset);
|
||||
var result = await _rpcClientService.CallGenericBoolResultAsync("NvService", "ApplyPresetWithResult", Preset);
|
||||
}
|
||||
|
||||
private void HdmiSettingsOnInput(ChangeEventArgs e)
|
||||
@@ -864,4 +967,30 @@
|
||||
{
|
||||
await _localStorage.SetAsync($"{nameof(NvPreset)}_{nameof(ApplyImmediately)}", ApplyImmediately);
|
||||
}
|
||||
|
||||
private async Task AfterVcpChanged(DdcSetting ddcSetting)
|
||||
{
|
||||
SkipNextApply = true;
|
||||
if (Preset?.IsDisplayPreset != true || Preset.DisplayId == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var result = await _rpcClientService.CallAsync<GenericResult<VcpInfo>>("NvService", "GetVcpInfo", Preset.DisplayId, ddcSetting.VcpCode);
|
||||
|
||||
SkipNextApply = true;
|
||||
|
||||
if (result.HasResult)
|
||||
{
|
||||
DdcErrorMessage = null;
|
||||
ddcSetting.Value = result.Result.Value;
|
||||
ddcSetting.MaxValue = result.Result.MaxValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
DdcErrorMessage = result.ErrorMessages.FirstOrDefault();
|
||||
ddcSetting.Value = 0;
|
||||
ddcSetting.MaxValue = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -245,6 +245,10 @@ else
|
||||
{
|
||||
<li class="list-group-item p-1">Color profile: @preset.ColorProfileSettings.ProfileName</li>
|
||||
}
|
||||
@if (preset.DdcSettings.ApplyDdc && preset.DdcSettings.Settings.Count > 0)
|
||||
{
|
||||
<li class="list-group-item p-1">DDC: @preset.DdcSettings.Settings[0]</li>
|
||||
}
|
||||
</ul>
|
||||
</small>
|
||||
<small class="text-muted">@preset.shortcut</small>
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
@inject AppState AppState
|
||||
@inject NavigationManager _navigationManager
|
||||
@inject NotificationService _notificationService
|
||||
@inject JSHelper _jsHelper;
|
||||
@inject IHttpContextAccessor _httpContextAccessor
|
||||
|
||||
<PageTitle>Options</PageTitle>
|
||||
|
||||
@@ -81,9 +83,26 @@ else
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label" for="webUiPort">
|
||||
Web UI port
|
||||
Web UI port (use 0 for automatic assignment)
|
||||
</label>
|
||||
@if (IsChangingUiPort)
|
||||
{
|
||||
<div class="alert alert-warning mb-2" role="alert">
|
||||
Changing the UI port. If the UI is not reloaded correctly, close this window and relaunch the UI.
|
||||
</div>
|
||||
}
|
||||
<input class="form-control" type="number" @bind="config.UiPort" id="webUiPort" @bind:after="UiPortBlur">
|
||||
@if (config.CurrentUiPort > 0)
|
||||
{
|
||||
<div id="uiPortHelp" class="form-text">Currently listening on port @config.CurrentUiPort</div>
|
||||
}
|
||||
</div>
|
||||
<div class="mb-3 form-check">
|
||||
<input class="form-check-input" type="checkbox" @bind="config.UiAllowRemoteConnections" id="uiAllowRemoteConnections" @bind:after="UiAllowRemoteConnectionsChange">
|
||||
<label class="form-check-label" for="uiAllowRemoteConnections">
|
||||
Web UI: Allow remote connections
|
||||
</label>
|
||||
<div id="uiAllowRemoteConnectionsHelp" class="form-text">Allows or disallows remote connections to the UI. Only enable this if you want to access the UI from another device (eg. your phone) than the system ColorControl is running on</div>
|
||||
</div>
|
||||
<div class="mb-3 form-check">
|
||||
<input class="form-check-input" type="checkbox" @bind="config.MinimizeOnClose" id="minimizeOnClose" @oninput="MinimizeOnCloseInput">
|
||||
@@ -183,10 +202,13 @@ else
|
||||
|
||||
@code {
|
||||
private Config? config;
|
||||
private bool IsEmbeddedBrowser;
|
||||
private bool IsChangingUiPort;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
config = await _rpcClientService.CallAsync<Config>("OptionsService", "GetConfig");
|
||||
IsEmbeddedBrowser = _httpContextAccessor.HttpContext?.Request.Headers["user-agent"].ToString().Contains("ColorControlEmbedded") == true;
|
||||
}
|
||||
|
||||
private async Task SaveConfig()
|
||||
@@ -313,6 +335,39 @@ else
|
||||
|
||||
private async Task UiPortBlur()
|
||||
{
|
||||
await _rpcClientService.CallAsync<bool>("OptionsService", "SetUiPort", config!.UiPort);
|
||||
if (config == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
IsChangingUiPort = true;
|
||||
|
||||
if (config.UiPort > 0 || IsEmbeddedBrowser)
|
||||
{
|
||||
await NavigateToNewPort(config.UiPort, 5000);
|
||||
}
|
||||
|
||||
var result = await _rpcClientService.CallAsync<bool>("OptionsService", "SetUiPort", config.UiPort);
|
||||
}
|
||||
|
||||
private async Task UiAllowRemoteConnectionsChange()
|
||||
{
|
||||
await _rpcClientService.CallAsync<bool>("OptionsService", "SetUiAllowRemoteConnections", config!.UiAllowRemoteConnections);
|
||||
}
|
||||
|
||||
private async Task NavigateToNewPort(int port, int timeout = 0)
|
||||
{
|
||||
var uri = new UriBuilder(_navigationManager.Uri);
|
||||
uri.Port = port;
|
||||
var newUri = uri.Uri.ToString();
|
||||
|
||||
if (timeout == 0)
|
||||
{
|
||||
_navigationManager.NavigateTo(uri.ToString(), true);
|
||||
}
|
||||
else
|
||||
{
|
||||
await _jsHelper.NavigateTo(newUri, timeout);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -34,6 +34,11 @@ public class JSHelper(IJSRuntime jsRuntime)
|
||||
await InvokeVoidAsync("ShowToast", id);
|
||||
}
|
||||
|
||||
public async Task NavigateTo(string uri, int timeout = 0)
|
||||
{
|
||||
await InvokeVoidAsync("NavigateTo", uri, timeout);
|
||||
}
|
||||
|
||||
public async Task<RectDimension> GetElementDimensions(string id)
|
||||
{
|
||||
jsModule = await LoadModule();
|
||||
|
||||
@@ -7,83 +7,93 @@ namespace ColorControl.UI.Services;
|
||||
|
||||
public class RpcUiClientOptions
|
||||
{
|
||||
public int Timeout { get; set; } = PipeUtils.DefaultTimeout;
|
||||
public int Timeout { get; set; } = PipeUtils.DefaultTimeout;
|
||||
}
|
||||
|
||||
public class RpcUiClientService(NotificationService notificationService)
|
||||
{
|
||||
public string? LastErrorMessage { get; private set; }
|
||||
public string? LastErrorMessage { get; private set; }
|
||||
|
||||
public async Task<T> CallAsync<T>(string serviceName, string method, params object?[] arguments)
|
||||
{
|
||||
var rpcMessage = new SvcRpcMessage
|
||||
{
|
||||
ServiceName = serviceName,
|
||||
MethodName = method,
|
||||
Arguments = arguments
|
||||
};
|
||||
public async Task<T> CallAsync<T>(string serviceName, string method, params object?[] arguments)
|
||||
{
|
||||
var rpcMessage = new SvcRpcMessage
|
||||
{
|
||||
ServiceName = serviceName,
|
||||
MethodName = method,
|
||||
Arguments = arguments
|
||||
};
|
||||
|
||||
var timeout = Debugger.IsAttached ? 60000 : PipeUtils.DefaultTimeout;
|
||||
var timeout = Debugger.IsAttached ? 60000 : PipeUtils.DefaultTimeout;
|
||||
|
||||
return await SendRpcMessageAsync<T>(rpcMessage, timeout, pipeName: PipeUtils.MainPipe);
|
||||
}
|
||||
return await SendRpcMessageAsync<T>(rpcMessage, timeout, pipeName: PipeUtils.MainPipe);
|
||||
}
|
||||
|
||||
public async Task<T> CallWithOptionsAsync<T>(string serviceName, string method, RpcUiClientOptions options, params object?[] arguments)
|
||||
{
|
||||
var rpcMessage = new SvcRpcMessage
|
||||
{
|
||||
ServiceName = serviceName,
|
||||
MethodName = method,
|
||||
Arguments = arguments
|
||||
};
|
||||
public async Task<bool> CallGenericBoolResultAsync(string serviceName, string method, params object?[] arguments)
|
||||
{
|
||||
var rpcMessage = new SvcRpcMessage
|
||||
{
|
||||
ServiceName = serviceName,
|
||||
MethodName = method,
|
||||
Arguments = arguments
|
||||
};
|
||||
|
||||
return await SendRpcMessageAsync<T>(rpcMessage, options.Timeout, pipeName: PipeUtils.MainPipe);
|
||||
}
|
||||
var timeout = Debugger.IsAttached ? 60000 : PipeUtils.DefaultTimeout;
|
||||
|
||||
public T Call<T>(string serviceName, string method, params object[] arguments)
|
||||
{
|
||||
var rpcMessage = new SvcRpcMessage
|
||||
{
|
||||
ServiceName = serviceName,
|
||||
MethodName = method,
|
||||
Arguments = arguments
|
||||
};
|
||||
var result = await SendRpcMessageAsync<GenericBoolResult>(rpcMessage, timeout, pipeName: PipeUtils.MainPipe);
|
||||
|
||||
var timeout = Debugger.IsAttached ? 60000 : 2000;
|
||||
if (result?.Result == true)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return PipeUtils.SendRpcMessage<T>(rpcMessage, timeout, pipeName: PipeUtils.MainPipe);
|
||||
}
|
||||
if (result?.ErrorMessages.Count > 0)
|
||||
{
|
||||
await notificationService.SendNotificationDirect(new NotificationDto(result.ErrorMessages.First(), Constants.Danger));
|
||||
}
|
||||
|
||||
private async Task<T> SendRpcMessageAsync<T>(SvcRpcMessage message, int timeout = PipeUtils.DefaultTimeout, string pipeName = PipeUtils.ServicePipe)
|
||||
{
|
||||
var messageJson = JsonConvert.SerializeObject(message);
|
||||
return false;
|
||||
}
|
||||
|
||||
var resultJson = await PipeUtils.SendMessageAsync(messageJson, timeout, pipeName);
|
||||
public async Task<T> CallWithOptionsAsync<T>(string serviceName, string method, RpcUiClientOptions options, params object?[] arguments)
|
||||
{
|
||||
var rpcMessage = new SvcRpcMessage
|
||||
{
|
||||
ServiceName = serviceName,
|
||||
MethodName = method,
|
||||
Arguments = arguments
|
||||
};
|
||||
|
||||
if (resultJson == null)
|
||||
{
|
||||
notificationService.SendNotification(new NotificationDto("Unknown communication error", Constants.Danger));
|
||||
return await SendRpcMessageAsync<T>(rpcMessage, options.Timeout, pipeName: PipeUtils.MainPipe);
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
private async Task<T> SendRpcMessageAsync<T>(SvcRpcMessage message, int timeout = PipeUtils.DefaultTimeout, string pipeName = PipeUtils.ServicePipe)
|
||||
{
|
||||
var messageJson = JsonConvert.SerializeObject(message);
|
||||
|
||||
var resultMessage = JsonConvert.DeserializeObject<SvcResultMessage>(resultJson);
|
||||
var resultJson = await PipeUtils.SendMessageAsync(messageJson, timeout, pipeName);
|
||||
|
||||
if (resultMessage?.Data == null)
|
||||
{
|
||||
LastErrorMessage = resultMessage?.ErrorMessage ?? "Unknown communication error";
|
||||
if (resultJson == null)
|
||||
{
|
||||
notificationService.SendNotification(new NotificationDto("Unknown communication error", Constants.Danger));
|
||||
|
||||
await notificationService.SendNotificationDirect(new NotificationDto(LastErrorMessage, Constants.Danger));
|
||||
return default;
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
var resultMessage = JsonConvert.DeserializeObject<SvcResultMessage>(resultJson);
|
||||
|
||||
LastErrorMessage = null;
|
||||
if (resultMessage?.Data == null)
|
||||
{
|
||||
LastErrorMessage = resultMessage?.ErrorMessage ?? "Unknown communication error";
|
||||
|
||||
var result = JsonConvert.DeserializeObject<T>(resultMessage.Data);
|
||||
await notificationService.SendNotificationDirect(new NotificationDto(LastErrorMessage, Constants.Danger));
|
||||
|
||||
return result;
|
||||
}
|
||||
return default;
|
||||
}
|
||||
|
||||
LastErrorMessage = null;
|
||||
|
||||
var result = JsonConvert.DeserializeObject<T>(resultMessage.Data);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -22,4 +22,8 @@ export function GetElementDimensions(elementId) {
|
||||
|
||||
export function GetElementClassName(elementId) {
|
||||
return document.getElementById(elementId).className;
|
||||
}
|
||||
|
||||
export function NavigateTo(uri, timeout = 0) {
|
||||
setTimeout(() => window.location = uri, timeout);
|
||||
}
|
||||
Reference in new issue
Block a user