mirror of
https://github.com/Maassoft/ColorControl.git
synced 2026-10-22 00:22:18 -05:00
fix some issues and add test Blazor frontend
This commit is contained in:
1 parent
27bc0505b7
commit
9a9424f1af
41 files changed
+1049
-23
No files matched your search
@@ -0,0 +1,38 @@
|
||||
using ColorControl.Shared.Services;
|
||||
|
||||
namespace ColorControl.UI;
|
||||
|
||||
public static class Blazor
|
||||
{
|
||||
public static void Start()
|
||||
{
|
||||
var builder = WebApplication.CreateBuilder();
|
||||
|
||||
// Add services to the container.
|
||||
builder.Services.AddRazorComponents()
|
||||
.AddInteractiveServerComponents();
|
||||
|
||||
builder.Services.AddSingleton<AppState>();
|
||||
builder.Services.AddSingleton<OptionsService>();
|
||||
|
||||
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();
|
||||
|
||||
app.Run();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0-windows10.0.20348.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<OutputType>Library</OutputType>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Shared\Shared.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,35 @@
|
||||
@inject AppState AppState
|
||||
@implements IDisposable
|
||||
@attribute [StreamRendering]
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" data-bs-theme="@AppState.SelectedTheme">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<base href="/" />
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-4bw+/aepP/YC94hEpVNVgiZdgIC5+VKNBQNGCHeKRQN+PtmoHDEXuppvnDJzQIu9" crossorigin="anonymous">
|
||||
<link rel="stylesheet" href="app.css" />
|
||||
<link rel="stylesheet" href="ColorControl.UI.styles.css" />
|
||||
<link rel="icon" type="image/png" href="favicon.png" />
|
||||
<HeadOutlet />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<Routes />
|
||||
<script src="_framework/blazor.web.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@code {
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
AppState.OnChange += StateHasChanged;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
AppState.OnChange -= StateHasChanged;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
@inherits LayoutComponentBase
|
||||
|
||||
<div class="page">
|
||||
<div class="sidebar">
|
||||
<NavMenu />
|
||||
</div>
|
||||
|
||||
<main>
|
||||
<TopMenu />
|
||||
|
||||
<article class="content px-4">
|
||||
@Body
|
||||
</article>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<div id="blazor-error-ui">
|
||||
An unhandled error has occurred.
|
||||
<a href="" class="reload">Reload</a>
|
||||
<a class="dismiss">🗙</a>
|
||||
</div>
|
||||
@@ -0,0 +1,96 @@
|
||||
.page {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
main {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
background-image: linear-gradient(180deg, rgb(0, 40, 90) 0%, #101047 70%);
|
||||
}
|
||||
|
||||
.top-row {
|
||||
background-color: #f7f7f7;
|
||||
border-bottom: 1px solid #d6d5d5;
|
||||
justify-content: flex-end;
|
||||
height: 3.5rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.top-row ::deep a, .top-row ::deep .btn-link {
|
||||
white-space: nowrap;
|
||||
margin-left: 1.5rem;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.top-row ::deep a:hover, .top-row ::deep .btn-link:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.top-row ::deep a:first-child {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
@media (max-width: 640.98px) {
|
||||
.top-row {
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.top-row ::deep a, .top-row ::deep .btn-link {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 641px) {
|
||||
.page {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
width: 250px;
|
||||
height: 100vh;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.top-row {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.top-row.auth ::deep a:first-child {
|
||||
flex: 1;
|
||||
text-align: right;
|
||||
width: 0;
|
||||
}
|
||||
|
||||
.top-row, article {
|
||||
padding-left: 2rem !important;
|
||||
padding-right: 1.5rem !important;
|
||||
}
|
||||
}
|
||||
|
||||
#blazor-error-ui {
|
||||
background: lightyellow;
|
||||
bottom: 0;
|
||||
box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
|
||||
display: none;
|
||||
left: 0;
|
||||
padding: 0.6rem 1.25rem 0.7rem 1.25rem;
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
#blazor-error-ui .dismiss {
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
right: 0.75rem;
|
||||
top: 0.5rem;
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<div class="top-row ps-3 navbar navbar-dark">
|
||||
<div class="container-fluid">
|
||||
<a class="navbar-brand" href="">ColorControl Web App</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<input type="checkbox" title="Navigation menu" class="navbar-toggler" />
|
||||
|
||||
<div class="nav-scrollable" onclick="document.querySelector('.navbar-toggler').click()">
|
||||
<nav class="flex-column">
|
||||
<div class="nav-item px-3">
|
||||
<NavLink class="nav-link" href="" Match="NavLinkMatch.All">
|
||||
<span class="bi bi-house-door-fill-nav-menu" aria-hidden="true"></span> Home
|
||||
</NavLink>
|
||||
</div>
|
||||
|
||||
<div class="nav-item px-3">
|
||||
<NavLink class="nav-link" href="counter">
|
||||
<span class="bi bi-plus-square-fill-nav-menu" aria-hidden="true"></span> Counter
|
||||
</NavLink>
|
||||
</div>
|
||||
|
||||
<div class="nav-item px-3">
|
||||
<NavLink class="nav-link" href="weather">
|
||||
<span class="bi bi-list-nested-nav-menu" aria-hidden="true"></span> Weather
|
||||
</NavLink>
|
||||
</div>
|
||||
|
||||
<div class="nav-item px-3">
|
||||
<NavLink class="nav-link" href="options">
|
||||
<span class="bi bi-plus-square-fill-nav-menu" aria-hidden="true"></span> Options
|
||||
</NavLink>
|
||||
</div>
|
||||
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
.navbar-toggler {
|
||||
appearance: none;
|
||||
cursor: pointer;
|
||||
width: 3.5rem;
|
||||
height: 2.5rem;
|
||||
color: white;
|
||||
position: absolute;
|
||||
top: 0.5rem;
|
||||
right: 1rem;
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
background: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e") no-repeat center/1.75rem rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.navbar-toggler:checked {
|
||||
background-color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
.top-row {
|
||||
height: 3.5rem;
|
||||
background-color: rgba(0,0,0,0.4);
|
||||
}
|
||||
|
||||
.navbar-brand {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.bi {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
width: 1.25rem;
|
||||
height: 1.25rem;
|
||||
margin-right: 0.75rem;
|
||||
top: -1px;
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
.bi-house-door-fill-nav-menu {
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-house-door-fill' viewBox='0 0 16 16'%3E%3Cpath d='M6.5 14.5v-3.505c0-.245.25-.495.5-.495h2c.25 0 .5.25.5.5v3.5a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5v-7a.5.5 0 0 0-.146-.354L13 5.793V2.5a.5.5 0 0 0-.5-.5h-1a.5.5 0 0 0-.5.5v1.293L8.354 1.146a.5.5 0 0 0-.708 0l-6 6A.5.5 0 0 0 1.5 7.5v7a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5Z'/%3E%3C/svg%3E");
|
||||
}
|
||||
|
||||
.bi-plus-square-fill-nav-menu {
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-plus-square-fill' viewBox='0 0 16 16'%3E%3Cpath d='M2 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2H2zm6.5 4.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3a.5.5 0 0 1 1 0z'/%3E%3C/svg%3E");
|
||||
}
|
||||
|
||||
.bi-list-nested-nav-menu {
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-list-nested' viewBox='0 0 16 16'%3E%3Cpath fill-rule='evenodd' d='M4.5 11.5A.5.5 0 0 1 5 11h10a.5.5 0 0 1 0 1H5a.5.5 0 0 1-.5-.5zm-2-4A.5.5 0 0 1 3 7h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5zm-2-4A.5.5 0 0 1 1 3h10a.5.5 0 0 1 0 1H1a.5.5 0 0 1-.5-.5z'/%3E%3C/svg%3E");
|
||||
}
|
||||
|
||||
.nav-item {
|
||||
font-size: 0.9rem;
|
||||
padding-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.nav-item:first-of-type {
|
||||
padding-top: 1rem;
|
||||
}
|
||||
|
||||
.nav-item:last-of-type {
|
||||
padding-bottom: 1rem;
|
||||
}
|
||||
|
||||
.nav-item ::deep .nav-link {
|
||||
color: #d7d7d7;
|
||||
background: none;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
height: 3rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
line-height: 3rem;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.nav-item ::deep a.active {
|
||||
background-color: rgba(255,255,255,0.37);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.nav-item ::deep .nav-link:hover {
|
||||
background-color: rgba(255,255,255,0.1);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.nav-scrollable {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.navbar-toggler:checked ~ .nav-scrollable {
|
||||
display: block;
|
||||
}
|
||||
|
||||
@media (min-width: 641px) {
|
||||
.navbar-toggler {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.nav-scrollable {
|
||||
/* Never collapse the sidebar for wide screens */
|
||||
display: block;
|
||||
|
||||
/* Allow sidebar to scroll for tall menus */
|
||||
height: calc(100vh - 3.5rem);
|
||||
overflow-y: auto;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
@inherits LayoutComponentBase
|
||||
|
||||
@inject AppState AppState
|
||||
@inject NavigationManager _navigationManager;
|
||||
@rendermode InteractiveServer
|
||||
|
||||
<div class="top-row px-4 pt-2">
|
||||
<button type="button" class="btn btn-primary me-2" @onclick="ChangeTheme">@ThemeTransitionName</button>
|
||||
<a href="https://github.com/Maassoft/ColorControl" target="_blank">GitHub</a>
|
||||
</div>
|
||||
|
||||
@code {
|
||||
|
||||
private string ThemeTransitionName = "Dark";
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
ThemeTransitionName = AppState.SelectedTheme == "light" ? "Dark theme" : "Light theme";
|
||||
}
|
||||
|
||||
private void ChangeTheme()
|
||||
{
|
||||
AppState.SetTheme(AppState.SelectedTheme == "light" ? "dark" : "light");
|
||||
ThemeTransitionName = AppState.SelectedTheme == "light" ? "Dark theme" : "Light theme";
|
||||
_navigationManager.Refresh();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
.navbar-toggler {
|
||||
appearance: none;
|
||||
cursor: pointer;
|
||||
width: 3.5rem;
|
||||
height: 2.5rem;
|
||||
color: white;
|
||||
position: absolute;
|
||||
top: 0.5rem;
|
||||
right: 1rem;
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
background: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e") no-repeat center/1.75rem rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.navbar-toggler:checked {
|
||||
background-color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
.top-row {
|
||||
height: 3.5rem;
|
||||
background-color: rgba(0,0,0,0.4);
|
||||
}
|
||||
|
||||
.navbar-brand {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.bi {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
width: 1.25rem;
|
||||
height: 1.25rem;
|
||||
margin-right: 0.75rem;
|
||||
top: -1px;
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
.bi-house-door-fill-nav-menu {
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-house-door-fill' viewBox='0 0 16 16'%3E%3Cpath d='M6.5 14.5v-3.505c0-.245.25-.495.5-.495h2c.25 0 .5.25.5.5v3.5a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5v-7a.5.5 0 0 0-.146-.354L13 5.793V2.5a.5.5 0 0 0-.5-.5h-1a.5.5 0 0 0-.5.5v1.293L8.354 1.146a.5.5 0 0 0-.708 0l-6 6A.5.5 0 0 0 1.5 7.5v7a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5Z'/%3E%3C/svg%3E");
|
||||
}
|
||||
|
||||
.bi-plus-square-fill-nav-menu {
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-plus-square-fill' viewBox='0 0 16 16'%3E%3Cpath d='M2 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2H2zm6.5 4.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3a.5.5 0 0 1 1 0z'/%3E%3C/svg%3E");
|
||||
}
|
||||
|
||||
.bi-list-nested-nav-menu {
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-list-nested' viewBox='0 0 16 16'%3E%3Cpath fill-rule='evenodd' d='M4.5 11.5A.5.5 0 0 1 5 11h10a.5.5 0 0 1 0 1H5a.5.5 0 0 1-.5-.5zm-2-4A.5.5 0 0 1 3 7h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5zm-2-4A.5.5 0 0 1 1 3h10a.5.5 0 0 1 0 1H1a.5.5 0 0 1-.5-.5z'/%3E%3C/svg%3E");
|
||||
}
|
||||
|
||||
.nav-item {
|
||||
font-size: 0.9rem;
|
||||
padding-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.nav-item:first-of-type {
|
||||
padding-top: 1rem;
|
||||
}
|
||||
|
||||
.nav-item:last-of-type {
|
||||
padding-bottom: 1rem;
|
||||
}
|
||||
|
||||
.nav-item ::deep .nav-link {
|
||||
color: #d7d7d7;
|
||||
background: none;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
height: 3rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
line-height: 3rem;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.nav-item ::deep a.active {
|
||||
background-color: rgba(255,255,255,0.37);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.nav-item ::deep .nav-link:hover {
|
||||
background-color: rgba(255,255,255,0.1);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.nav-scrollable {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.navbar-toggler:checked ~ .nav-scrollable {
|
||||
display: block;
|
||||
}
|
||||
|
||||
@media (min-width: 641px) {
|
||||
.navbar-toggler {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.nav-scrollable {
|
||||
/* Never collapse the sidebar for wide screens */
|
||||
display: block;
|
||||
|
||||
/* Allow sidebar to scroll for tall menus */
|
||||
height: calc(100vh - 3.5rem);
|
||||
overflow-y: auto;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
@page "/counter"
|
||||
@rendermode InteractiveServer
|
||||
|
||||
<PageTitle>Counter</PageTitle>
|
||||
|
||||
<h1>Counter</h1>
|
||||
|
||||
<p role="status">Current count: @currentCount</p>
|
||||
|
||||
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
|
||||
|
||||
@code {
|
||||
private int currentCount = 0;
|
||||
|
||||
private void IncrementCount()
|
||||
{
|
||||
currentCount++;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
@page "/Error"
|
||||
@using System.Diagnostics
|
||||
|
||||
<PageTitle>Error</PageTitle>
|
||||
|
||||
<h1 class="text-danger">Error.</h1>
|
||||
<h2 class="text-danger">An error occurred while processing your request.</h2>
|
||||
|
||||
@if (ShowRequestId)
|
||||
{
|
||||
<p>
|
||||
<strong>Request ID:</strong> <code>@RequestId</code>
|
||||
</p>
|
||||
}
|
||||
|
||||
<h3>Development Mode</h3>
|
||||
<p>
|
||||
Swapping to <strong>Development</strong> environment will display more detailed information about the error that occurred.
|
||||
</p>
|
||||
<p>
|
||||
<strong>The Development environment shouldn't be enabled for deployed applications.</strong>
|
||||
It can result in displaying sensitive information from exceptions to end users.
|
||||
For local debugging, enable the <strong>Development</strong> environment by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong>
|
||||
and restarting the app.
|
||||
</p>
|
||||
|
||||
@code{
|
||||
[CascadingParameter]
|
||||
private HttpContext? HttpContext { get; set; }
|
||||
|
||||
private string? RequestId { get; set; }
|
||||
private bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
|
||||
|
||||
protected override void OnInitialized() =>
|
||||
RequestId = Activity.Current?.Id ?? HttpContext?.TraceIdentifier;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
@page "/"
|
||||
|
||||
<PageTitle>Home</PageTitle>
|
||||
|
||||
<h1>Hello, world!</h1>
|
||||
|
||||
Welcome to your new app.
|
||||
@@ -0,0 +1,52 @@
|
||||
@page "/options"
|
||||
@using ColorControl.Shared.Contracts
|
||||
@using ColorControl.Shared.Services;
|
||||
@rendermode InteractiveServer
|
||||
@inject OptionsService _optionsService
|
||||
|
||||
<PageTitle>Options</PageTitle>
|
||||
|
||||
<h1>Options</h1>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">General</h5>
|
||||
</div>
|
||||
<form class="ms-3">
|
||||
<div class="mb-3 form-check">
|
||||
<input class="form-check-input" type="checkbox" @bind="config.AutoStart" id="startAfterLogin">
|
||||
<label class="form-check-label" for="startAfterLogin">
|
||||
Automatically start after login
|
||||
</label>
|
||||
</div>
|
||||
<div class="mb-3 form-check">
|
||||
<input class="form-check-input" type="checkbox" @bind="config.StartMinimized" id="startMinimized">
|
||||
<label class="form-check-label" for="startMinimized">
|
||||
Start minimized
|
||||
</label>
|
||||
</div>
|
||||
<div class="mb-3 form-check">
|
||||
<input class="form-check-input" type="checkbox" @bind="config.MinimizeToTray" id="minimizeToTray">
|
||||
<label class="form-check-label" for="minimizeToTray">
|
||||
Minimize to tray
|
||||
</label>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<button class="btn btn-primary" @onclick="SaveConfig">Save</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@code {
|
||||
private Config config;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
config = _optionsService.GetConfig();
|
||||
}
|
||||
|
||||
private void SaveConfig()
|
||||
{
|
||||
_optionsService.SetConfig(config);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
@page "/weather"
|
||||
@attribute [StreamRendering]
|
||||
|
||||
<PageTitle>Weather</PageTitle>
|
||||
|
||||
<h1>Weather</h1>
|
||||
|
||||
<p>This component demonstrates showing data.</p>
|
||||
|
||||
@if (forecasts == null)
|
||||
{
|
||||
<p><em>Loading...</em></p>
|
||||
}
|
||||
else
|
||||
{
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Date</th>
|
||||
<th>Temp. (C)</th>
|
||||
<th>Temp. (F)</th>
|
||||
<th>Summary</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var forecast in forecasts)
|
||||
{
|
||||
<tr>
|
||||
<td>@forecast.Date.ToShortDateString()</td>
|
||||
<td>@forecast.TemperatureC</td>
|
||||
<td>@forecast.TemperatureF</td>
|
||||
<td>@forecast.Summary</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
}
|
||||
|
||||
@code {
|
||||
private WeatherForecast[]? forecasts;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
// Simulate asynchronous loading to demonstrate streaming rendering
|
||||
await Task.Delay(500);
|
||||
|
||||
var startDate = DateOnly.FromDateTime(DateTime.Now);
|
||||
var summaries = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" };
|
||||
forecasts = Enumerable.Range(1, 5).Select(index => new WeatherForecast
|
||||
{
|
||||
Date = startDate.AddDays(index),
|
||||
TemperatureC = Random.Shared.Next(-20, 55),
|
||||
Summary = summaries[Random.Shared.Next(summaries.Length)]
|
||||
}).ToArray();
|
||||
}
|
||||
|
||||
private class WeatherForecast
|
||||
{
|
||||
public DateOnly Date { get; set; }
|
||||
public int TemperatureC { get; set; }
|
||||
public string? Summary { get; set; }
|
||||
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
<Router AppAssembly="@typeof(Blazor).Assembly">
|
||||
<Found Context="routeData">
|
||||
<RouteView RouteData="@routeData" DefaultLayout="@typeof(Layout.MainLayout)" />
|
||||
<FocusOnNavigate RouteData="@routeData" Selector="h1" />
|
||||
</Found>
|
||||
</Router>
|
||||
@@ -0,0 +1,10 @@
|
||||
@using System.Net.Http
|
||||
@using System.Net.Http.Json
|
||||
@using Microsoft.AspNetCore.Components.Forms
|
||||
@using Microsoft.AspNetCore.Components.Routing
|
||||
@using Microsoft.AspNetCore.Components.Web
|
||||
@using static Microsoft.AspNetCore.Components.Web.RenderMode
|
||||
@using Microsoft.AspNetCore.Components.Web.Virtualization
|
||||
@using Microsoft.JSInterop
|
||||
@using ColorControl.UI
|
||||
@using ColorControl.UI.Components
|
||||
@@ -0,0 +1,32 @@
|
||||
//using ColorControl.UI;
|
||||
|
||||
//Blazor.Start();
|
||||
|
||||
//var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
//// Add services to the container.
|
||||
//builder.Services.AddRazorComponents()
|
||||
// .AddInteractiveServerComponents();
|
||||
|
||||
//builder.Services.AddSingleton<AppState>();
|
||||
//builder.Services.AddSingleton<OptionsService>();
|
||||
|
||||
//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<App>()
|
||||
// .AddInteractiveServerRenderMode();
|
||||
|
||||
//app.Run();
|
||||
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"$schema": "http://json.schemastore.org/launchsettings.json",
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:31433",
|
||||
"sslPort": 44330
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"http": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": true,
|
||||
"applicationUrl": "http://localhost:5175",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"https": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": true,
|
||||
"applicationUrl": "https://localhost:7135;http://localhost:5175",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": true,
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
namespace ColorControl.UI;
|
||||
|
||||
public class AppState
|
||||
{
|
||||
public string SelectedTheme { get; private set; } = "light";
|
||||
|
||||
public event Action? OnChange;
|
||||
|
||||
public void SetTheme(string theme)
|
||||
{
|
||||
SelectedTheme = theme;
|
||||
NotifyStateChanged();
|
||||
}
|
||||
|
||||
private void NotifyStateChanged() => OnChange?.Invoke();
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*"
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
html, body {
|
||||
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
}
|
||||
|
||||
a, .btn-link {
|
||||
color: #006bb7;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
color: #fff;
|
||||
background-color: #1b6ec2;
|
||||
border-color: #1861ac;
|
||||
}
|
||||
|
||||
.btn:focus, .btn:active:focus, .btn-link.nav-link:focus, .form-control:focus, .form-check-input:focus {
|
||||
box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem #258cfb;
|
||||
}
|
||||
|
||||
.content {
|
||||
padding-top: 1.1rem;
|
||||
}
|
||||
|
||||
h1:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.valid.modified:not([type=checkbox]) {
|
||||
outline: 1px solid #26b050;
|
||||
}
|
||||
|
||||
.invalid {
|
||||
outline: 1px solid #e50000;
|
||||
}
|
||||
|
||||
.validation-message {
|
||||
color: #e50000;
|
||||
}
|
||||
|
||||
.blazor-error-boundary {
|
||||
background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121;
|
||||
padding: 1rem 1rem 1rem 3.7rem;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.blazor-error-boundary::after {
|
||||
content: "An error has occurred."
|
||||
}
|
||||
|
||||
.darker-border-checkbox.form-check-input {
|
||||
border-color: #929292;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
@charset "UTF-8";/*!
|
||||
* Bootstrap v5.1.0 (https://getbootstrap.com/)
|
||||
* Copyright 2011-2021 The Bootstrap Authors
|
||||
* Copyright 2011-2021 Twitter, Inc.
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
||||
*/:root{--bs-blue:#0d6efd;--bs-indigo:#6610f2;--bs-purple:#6f42c1;--bs-pink:#d63384;--bs-red:#dc3545;--bs-orange:#fd7e14;--bs-yellow:#ffc107;--bs-green:#198754;--bs-teal:#20c997;--bs-cyan:#0dcaf0;--bs-white:#fff;--bs-gray:#6c757d;--bs-gray-dark:#343a40;--bs-gray-100:#f8f9fa;--bs-gray-200:#e9ecef;--bs-gray-300:#dee2e6;--bs-gray-400:#ced4da;--bs-gray-500:#adb5bd;--bs-gray-600:#6c757d;--bs-gray-700:#495057;--bs-gray-800:#343a40;--bs-gray-900:#212529;--bs-primary:#0d6efd;--bs-secondary:#6c757d;--bs-success:#198754;--bs-info:#0dcaf0;--bs-warning:#ffc107;--bs-danger:#dc3545;--bs-light:#f8f9fa;--bs-dark:#212529;--bs-primary-rgb:13,110,253;--bs-secondary-rgb:108,117,125;--bs-success-rgb:25,135,84;--bs-info-rgb:13,202,240;--bs-warning-rgb:255,193,7;--bs-danger-rgb:220,53,69;--bs-light-rgb:248,249,250;--bs-dark-rgb:33,37,41;--bs-white-rgb:255,255,255;--bs-black-rgb:0,0,0;--bs-body-rgb:33,37,41;--bs-font-sans-serif:system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans","Liberation Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--bs-font-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--bs-gradient:linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));--bs-body-font-family:var(--bs-font-sans-serif);--bs-body-font-size:1rem;--bs-body-font-weight:400;--bs-body-line-height:1.5;--bs-body-color:#212529;--bs-body-bg:#fff}*,::after,::before{box-sizing:border-box}@media (prefers-reduced-motion:no-preference){:root{scroll-behavior:smooth}}body{margin:0;font-family:var(--bs-body-font-family);font-size:var(--bs-body-font-size);font-weight:var(--bs-body-font-weight);line-height:var(--bs-body-line-height);color:var(--bs-body-color);text-align:var(--bs-body-text-align);background-color:var(--bs-body-bg);-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}hr{margin:1rem 0;color:inherit;background-color:currentColor;border:0;opacity:.25}hr:not([size]){height:1px}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2}.h1,h1{font-size:calc(1.375rem + 1.5vw)}@media (min-width:1200px){.h1,h1{font-size:2.5rem}}.h2,h2{font-size:calc(1.325rem + .9vw)}@media (min-width:1200px){.h2,h2{font-size:2rem}}.h3,h3{font-size:calc(1.3rem + .6vw)}@media (min-width:1200px){.h3,h3{font-size:1.75rem}}.h4,h4{font-size:calc(1.275rem + .3vw)}@media (min-width:1200px){.h4,h4{font-size:1.5rem}}.h5,h5{font-size:1.25rem}.h6,h6{font-size:1rem}p{margin-top:0;margin-bottom:1rem}abbr[data-bs-original-title],abbr[title]{-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-left:2rem}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}.small,small{font-size:.875em}.mark,mark{padding:.2em;background-color:#fcf8e3}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#0d6efd;text-decoration:underline}a:hover{color:#0a58ca}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:var(--bs-font-monospace);font-size:1em;direction:ltr;unicode-bidi:bidi-override}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:.875em}pre code{font-size:inherit;color:inherit;word-break:normal}code{font-size:.875em;color:#d63384;word-wrap:break-word}a>code{color:inherit}kbd{padding:.2rem .4rem;font-size:.875em;color:#fff;background-color:#212529;border-radius:.2rem}kbd kbd{padding:0;font-size:1em;font-weight:700}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:#6c757d;text-align:left}th{text-align:inherit;text-align:-webkit-match-parent}tbody,td,tfoot,th,thead,tr{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]::-webkit-calendar-picker-indicator{display:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:left;width:100%;padding:0;margin-bottom:.5rem;font-size:calc(1.275rem + .3vw);line-height:inherit}@media (min-width:1200px){leLine truncated
|
||||
/*# sourceMappingURL=bootstrap.min.css.map */
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["../../scss/bootstrap.scss","../../scss/_root.scss","../../scss/_reboot.scss","dist/css/bootstrap.css","../../scss/vendor/_rfs.scss","../../scss/mixins/_border-radius.scss","../../scss/_type.scss","../../scss/mixins/_lists.scss","../../scss/_images.scss","../../scss/mixins/_image.scss","../../scss/_containers.scss","../../scss/mixins/_container.scss","../../scss/mixins/_breakpoints.scss","../../scss/_grid.scss","../../scss/mixins/_grid.scss","../../scss/_tables.scss","../../scss/mixins/_table-variants.scss","../../scss/forms/_labels.scss","../../scss/forms/_form-text.scss","../../scss/forms/_form-control.scss","../../scss/mixins/_transition.scss","../../scss/mixins/_gradients.scss","../../scss/forms/_form-select.scss","../../scss/forms/_form-check.scss","../../scss/forms/_form-range.scss","../../scss/forms/_floating-labels.scss","../../scss/forms/_input-group.scss","../../scss/mixins/_forms.scss","../../scss/_buttons.scss","../../scss/mixins/_buttons.scss","../../scss/_transitions.scss","../../scss/_dropdown.scss","../../scss/mixins/_caret.scss","../../scss/_button-group.scss","../../scss/_nav.scss","../../scss/_navbar.scss","../../scss/_card.scss","../../scss/_accordion.scss","../../scss/_breadcrumb.scss","../../scss/_pagination.scss","../../scss/mixins/_pagination.scss","../../scss/_badge.scss","../../scss/_alert.scss","../../scss/mixins/_alert.scss","../../scss/_progress.scss","../../scss/_list-group.scss","../../scss/mixins/_list-group.scss","../../scss/_close.scss","../../scss/_toasts.scss","../../scss/_modal.scss","../../scss/mixins/_backdrop.scss","../../scss/_tooltip.scss","../../scss/mixins/_reset-text.scss","../../scss/_popover.scss","../../scss/_carousel.scss","../../scss/mixins/_clearfix.scss","../../scss/_spinners.scss","../../scss/_offcanvas.scss","../../scss/_placeholders.scss","../../scss/helpers/_colored-links.scss","../../scss/helpers/_ratio.scss","../../scss/helpers/_position.scss","../../scss/helpers/_stacks.scss","../../scss/helpers/_visually-hidden.scss","../../scss/mixins/_visually-hidden.scss","../../scss/helpers/_stretched-link.scss","../../scss/helpers/_text-truncation.scss","../../scss/mixins/_text-truncate.scss","../../scss/helpers/_vr.scss","../../scss/mixins/_utilities.scss","../../scss/utilities/_api.scss"],"names":[],"mappings":"iBAAA;;;;;ACAA,MAQI,UAAA,QAAA,YAAA,QAAA,YAAA,QAAA,UAAA,QAAA,SAAA,QAAA,YAAA,QAAA,YAAA,QAAA,WAAA,QAAA,UAAA,QAAA,UAAA,QAAA,WAAA,KAAA,UAAA,QAAA,eAAA,QAIA,cAAA,QAAA,cAAA,QAAA,cAAA,QAAA,cAAA,QAAA,cAAA,QAAA,cAAA,QAAA,cAAA,QAAA,cAAA,QAAA,cAAA,QAIA,aAAA,QAAA,eAAA,QAAA,aAAA,QAAA,UAAA,QAAA,aAAA,QAAA,YAAA,QAAA,WAAA,QAAA,UAAA,QAIA,iBAAA,EAAA,CAAA,GAAA,CAAA,IAAA,mBAAA,GAAA,CAAA,GAAA,CAAA,IAAA,iBAAA,EAAA,CAAA,GAAA,CAAA,GAAA,cAAA,EAAA,CAAA,GAAA,CAAA,IAAA,iBAAA,GAAA,CAAA,GAAA,CAAA,EAAA,gBAAA,GAAA,CAAA,EAAA,CAAA,GAAA,eAAA,GAAA,CAAA,GAAA,CAAA,IAAA,cAAA,EAAA,CAAA,EAAA,CAAA,GAGF,eAAA,GAAA,CAAA,GAAA,CAAA,IACA,eAAA,CAAA,CAAA,CAAA,CAAA,EACA,cAAA,EAAA,CAAA,EAAA,CAAA,GAMA,qBAAA,SAAA,CAAA,aAAA,CAAA,UAAA,CAAA,MAAA,CAAA,gBAAA,CAAA,KAAA,CAAA,WAAA,CAAA,iBAAA,CAAA,UAAA,CAAA,mBAAA,CAAA,gBAAA,CAAA,iBAAA,CAAA,mBACA,oBAAA,cAAA,CAAA,KAAA,CAAA,MAAA,CAAA,QAAA,CAAA,iBAAA,CAAA,aAAA,CAAA,UACA,cAAA,2EAQA,sBAAA,0BACA,oBAAA,KACA,sBAAA,IACA,sBAAA,IACA,gBAAA,QAIA,aAAA,KClCF,EC+CA,QADA,SD3CE,WAAA,WAeE,8CANJ,MAOM,gBAAA,QAcN,KACE,OAAA,EACA,YAAA,2BEmPI,UAAA,yBFjPJ,YAAA,2BACA,YAAA,2BACA,MAAA,qBACA,WAAA,0BACA,iBAAA,kBACA,yBAAA,KACA,4BAAA,YAUF,GACE,OAAA,KAAA,EACA,MAAA,QACA,iBAAA,aACA,OAAA,EACA,QAAA,IAGF,eACE,OAAA,IAUF,IAAA,IAAA,IAAA,IAAA,IAAA,IAAA,GAAA,GAAA,GAAA,GAAA,GAAA,GACE,WAAA,EACA,cAAA,MAGA,YAAA,IACA,YAAA,IAIF,IAAA,GEwMQ,UAAA,uBAlKJ,0BFtCJ,IAAA,GE+MQ,UAAA,QF1MR,IAAA,GEmMQ,UAAA,sBAlKJ,0BFjCJ,IAAA,GE0MQ,UAAA,MFrMR,IAAA,GE8LQ,UAAA,oBAlKJ,0BF5BJ,IAAA,GEqMQ,UAAA,SFhMR,IAAA,GEyLQ,UAAA,sBAlKJ,0BFvBJ,IAAA,GEgMQ,UAAA,QF3LR,IAAA,GEgLM,UAAA,QF3KN,IAAA,GE2KM,UAAA,KFhKN,EACE,WAAA,EACA,cAAA,KCmBF,6BDRA,YAEE,wBAAA,UAAA,OAAA,gBAAA,UAAA,OACA,OAAA,KACA,iCAAA,KAAA,yBAAA,KAMF,QACE,cAAA,KACA,WAAA,OACA,YAAA,QAMF,GCIA,GDFE,aAAA,KCQF,GDLA,GCIA,GDDE,WAAA,EACA,cAAA,KAGF,MCKA,MACA,MAFA,MDAE,cAAA,EAGF,GACE,YAAA,IAKF,GACE,cAAA,MACA,YAAA,EAMF,WACE,OAAA,EAAA,EAAA,KAQF,ECNA,ODQE,YAAA,OAQF,OAAA,ME4EM,UAAA,OFrEN,MAAA,KACE,QAAA,KACA,iBAAA,QASF,ICpBA,IDsBE,SAAA,SEwDI,UAAA,MFtDJ,YAAA,EACA,eAAA,SAGF,IAAM,OAAA,OACN,IAAM,IAAA,MAKN,EACE,MAAA,QACA,gBAAA,UAEA,QACE,MAAA,QAWF,2BAAA,iCAEE,MAAA,QACA,gBAAA,KCxBJ,KACA,ID8BA,IC7BA,KDiCE,YAAA,yBEcI,UAAA,IFZJ,UAAA,IACA,aAAA,cAOF,IACE,QAAA,MACA,WAAA,EACA,cAAA,KACA,SAAA,KEAI,UAAA,OFKJ,SELI,UAAA,QFOF,MAAA,QACA,WAAA,OAIJ,KEZM,UAAA,OFcJ,MAAA,QACA,UAAA,WAGA,OACE,MAAA,QAIJ,IACE,QAAA,MAAA,MExBI,UAAA,OF0BJ,MAAA,KACA,iBAAA,QG7SE,cAAA,MHgTF,QACE,QAAA,EE/BE,UAAA,IFiCF,YAAA,IASJ,OACE,OAAA,EAAA,EAAA,KAMF,ICjDA,IDmDE,eAAA,OAQF,MACE,aAAA,OACA,gBAAA,SAGF,QACE,YAAA,MACA,eAAA,MACA,MAAA,QACA,WAAA,KAOF,GAEE,WAAA,QACA,WAAA,qBCxDF,MAGA,GAFA,MAGA,GDuDA,MCzDA,GD+DE,aAAA,QACA,aAAA,MACA,aAAA,EAQF,MACE,QAAA,aAMF,OAEE,cAAA,EAQF,iCACE,QAAA,ECtEF,OD2EA,MCzEA,SADA,OAEA,SD6EE,OAAA,EACA,YAAA,QE9HI,UAAA,QFgIJLine truncated
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
@@ -19,6 +19,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LittleCms", "LittleCms\Litt
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MHC2Gen", "MHC2Gen\MHC2Gen.csproj", "{9FDF741F-0ECF-46DB-8671-AB11ACEB9F41}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ColorControl.UI", "ColorControl.UI\ColorControl.UI.csproj", "{85EA3079-BB73-4CE5-A72F-E56906187051}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -91,6 +93,14 @@ Global
|
||||
{9FDF741F-0ECF-46DB-8671-AB11ACEB9F41}.Release|Any CPU.Build.0 = Release|x64
|
||||
{9FDF741F-0ECF-46DB-8671-AB11ACEB9F41}.Release|x64.ActiveCfg = Release|x64
|
||||
{9FDF741F-0ECF-46DB-8671-AB11ACEB9F41}.Release|x64.Build.0 = Release|x64
|
||||
{85EA3079-BB73-4CE5-A72F-E56906187051}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{85EA3079-BB73-4CE5-A72F-E56906187051}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{85EA3079-BB73-4CE5-A72F-E56906187051}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{85EA3079-BB73-4CE5-A72F-E56906187051}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{85EA3079-BB73-4CE5-A72F-E56906187051}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{85EA3079-BB73-4CE5-A72F-E56906187051}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{85EA3079-BB73-4CE5-A72F-E56906187051}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{85EA3079-BB73-4CE5-A72F-E56906187051}.Release|x64.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
@@ -127,6 +127,7 @@
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\ColorControl.UI\ColorControl.UI.csproj" />
|
||||
<ProjectReference Include="..\MHC2Gen\MHC2Gen.csproj" />
|
||||
<ProjectReference Include="..\NLogViewer\NLogViewer.csproj" />
|
||||
<ProjectReference Include="..\novideo_srgb\novideo_srgb.csproj" />
|
||||
|
||||
@@ -167,7 +167,7 @@ public partial class OptionsPanel : UserControl
|
||||
{
|
||||
if (_initialized)
|
||||
{
|
||||
_config.StartMinimized = chkStartMinimized.Checked;
|
||||
_config.MinimizeToTray = chkMinimizeToSystemTray.Checked;
|
||||
Program.GetNotifyIcon().Visible = _config.MinimizeToTray;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -212,6 +212,23 @@ namespace ColorControl
|
||||
Environment.Exit(0);
|
||||
}
|
||||
|
||||
private static bool UiServerStarted;
|
||||
|
||||
public static async Task OpenNewUi()
|
||||
{
|
||||
if (!UiServerStarted)
|
||||
{
|
||||
var _ = Task.Run(ColorControl.UI.Blazor.Start);
|
||||
UiServerStarted = true;
|
||||
|
||||
await Task.Delay(500);
|
||||
}
|
||||
|
||||
var winApi = AppContext.ServiceProvider.GetRequiredService<WinApiAdminService>();
|
||||
|
||||
winApi.StartProcess("http://localhost:5000");
|
||||
}
|
||||
|
||||
private static void InitLogger(bool runAsService, bool runElevated)
|
||||
{
|
||||
var config = new LoggingConfiguration();
|
||||
|
||||
@@ -7,6 +7,7 @@ using ColorControl.Services.Samsung;
|
||||
using ColorControl.Shared.Common;
|
||||
using ColorControl.Shared.Contracts;
|
||||
using ColorControl.Shared.Forms;
|
||||
using ColorControl.Shared.Services;
|
||||
using novideo_srgb;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -19,6 +20,8 @@ public class NotifyIconManager
|
||||
{
|
||||
private readonly GlobalContext _globalContext;
|
||||
private readonly ServiceManager _serviceManager;
|
||||
private readonly WinApiAdminService _winApiAdminService;
|
||||
private readonly WinApiService _winApiService;
|
||||
private readonly Config _config;
|
||||
|
||||
public NotifyIcon NotifyIcon { get; private set; }
|
||||
@@ -30,10 +33,15 @@ public class NotifyIconManager
|
||||
private ToolStripMenuItem _samsungTrayMenu;
|
||||
private ToolStripMenuItem _gameTrayMenu;
|
||||
|
||||
public NotifyIconManager(GlobalContext globalContext, ServiceManager serviceManager)
|
||||
private ToolStripMenuItem _stopServiceAndExitMenuItem;
|
||||
private ToolStripMenuItem _openNewUiMenuItem;
|
||||
|
||||
public NotifyIconManager(GlobalContext globalContext, ServiceManager serviceManager, WinApiAdminService winApiAdminService, WinApiService winApiService)
|
||||
{
|
||||
_globalContext = globalContext;
|
||||
_serviceManager = serviceManager;
|
||||
_winApiAdminService = winApiAdminService;
|
||||
_winApiService = winApiService;
|
||||
_config = globalContext.Config;
|
||||
}
|
||||
|
||||
@@ -68,8 +76,10 @@ public class NotifyIconManager
|
||||
_gameTrayMenu,
|
||||
new ToolStripSeparator(),
|
||||
new ToolStripMenuItem("Open", null, OpenForm),
|
||||
_openNewUiMenuItem = new ToolStripMenuItem("Open new UI", null, OpenNewUi),
|
||||
new ToolStripSeparator(),
|
||||
new ToolStripMenuItem("Restart", null, Restart),
|
||||
_stopServiceAndExitMenuItem = new ToolStripMenuItem("Stop Service And Exit", null, StopServiceAndExit),
|
||||
new ToolStripMenuItem("Exit", null, Exit)
|
||||
});
|
||||
|
||||
@@ -85,6 +95,13 @@ public class NotifyIconManager
|
||||
}
|
||||
}
|
||||
|
||||
private void StopServiceAndExit(object sender, EventArgs e)
|
||||
{
|
||||
_winApiAdminService.StopService();
|
||||
|
||||
Program.Exit();
|
||||
}
|
||||
|
||||
private void Exit(object sender, EventArgs e)
|
||||
{
|
||||
Program.Exit();
|
||||
@@ -100,6 +117,11 @@ public class NotifyIconManager
|
||||
Program.OpenMainForm();
|
||||
}
|
||||
|
||||
private async void OpenNewUi(object sender, EventArgs e)
|
||||
{
|
||||
await Program.OpenNewUi();
|
||||
}
|
||||
|
||||
private void trayIcon_MouseDoubleClick(object sender, MouseEventArgs e)
|
||||
{
|
||||
Program.OpenMainForm();
|
||||
@@ -158,6 +180,8 @@ public class NotifyIconManager
|
||||
|
||||
UpdateTrayMenu(_gameTrayMenu, presets, TrayMenuItemGame_Click);
|
||||
}
|
||||
|
||||
_stopServiceAndExitMenuItem.Visible = _winApiService.IsServiceRunning();
|
||||
}
|
||||
|
||||
private void UpdateTrayMenu(ToolStripMenuItem menu, IEnumerable<PresetBase> presets, EventHandler eventHandler)
|
||||
|
||||
@@ -111,6 +111,12 @@ public class ServiceManager
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (serviceName.Equals("StartCmd", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
_winApiAdminService.StartProcess(parameters[0], parameters.Length > 1 ? string.Join(" ", parameters.Skip(1)) : null, wait: true, useShellExecute: false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -455,6 +455,8 @@ namespace ColorControl.Services.LG
|
||||
SetModelYear();
|
||||
}
|
||||
|
||||
Logger.Debug($"LG TV with ip-address {IpAddress} has model name {ModelName}");
|
||||
|
||||
await _lgTvApi.SubscribeVolume(VolumeChanged);
|
||||
await _lgTvApi.SubscribePowerState(PowerStateChanged);
|
||||
await _lgTvApi.SubscribePictureSettings(PictureSettingsChanged);
|
||||
|
||||
@@ -47,6 +47,12 @@ namespace ColorControl.Services.Samsung
|
||||
HospitalityMenu
|
||||
}
|
||||
|
||||
public enum ExitServiceMenuType
|
||||
{
|
||||
Exit,
|
||||
Reboot
|
||||
}
|
||||
|
||||
public delegate void GenericDelegate(object sender);
|
||||
|
||||
class SamsungDevice
|
||||
@@ -233,7 +239,14 @@ namespace ColorControl.Services.Samsung
|
||||
|
||||
internal async Task PowerOffAsync()
|
||||
{
|
||||
await SendKeyAsync("KEY_POWER");
|
||||
try
|
||||
{
|
||||
await SendKeyAsync("KEY_POWER").WaitAsync(TimeSpan.FromSeconds(2)).ConfigureAwait(true);
|
||||
}
|
||||
catch (TimeoutException ex)
|
||||
{
|
||||
Logger.Debug($"Timeout when turning off tv: {ex.Message}");
|
||||
}
|
||||
|
||||
PoweredOn = false;
|
||||
PoweredOffAt = DateTimeOffset.Now;
|
||||
@@ -781,6 +794,7 @@ namespace ColorControl.Services.Samsung
|
||||
var preset1 = new SamsungPreset("ServiceMenuStep1", null, ["KEY_INFO", "KEY_FACTORY:2000"]);
|
||||
var preset2 = new SamsungPreset("ServiceMenuStep2", null, ["KEY_UP", "KEY_0", "KEY_0", "KEY_9", "KEY_8"]);
|
||||
var rebootPreset = new SamsungPreset("ServiceMenuStep4", null, ["KEY_POWER:5000", "WOL"]);
|
||||
var exitPreset = new SamsungPreset("ServiceMenuStep3", null, ["KEY_FACTORY:1000", "KEY_FACTORY"]);
|
||||
|
||||
await ExecutePresetWithProgressAsync(preset1, "Step 1: opening Service Menu. It is normal to see messages like 'Not Available'.");
|
||||
|
||||
@@ -797,18 +811,29 @@ namespace ColorControl.Services.Samsung
|
||||
await ExecutePresetWithProgressAsync(preset2, "Step 2: accessing Advanced Service Menu...");
|
||||
}
|
||||
|
||||
if (!MessageForms.ShowDialog($"Reboot TV - Final Step", new[] {
|
||||
new FieldDefinition
|
||||
{
|
||||
Label = "Reboot TV",
|
||||
SubLabel = "After you have made the necessary changes, click 'Reboot TV' to reboot the TV or click 'X' to close. If the TV turns not back on automatically, power it on manually.",
|
||||
FieldType = FieldType.Label
|
||||
} }, okButtonText: "Reboot TV").Any())
|
||||
var exitServiceMenuTypes = new[] { ExitServiceMenuType.Exit, ExitServiceMenuType.Reboot }.Select(t => Utils.GetDescription(t));
|
||||
|
||||
var exitServiceMenuTypeField = new FieldDefinition
|
||||
{
|
||||
Label = "Exit Service Menu Type",
|
||||
SubLabel = "Choose how to exit the service menu. You can either reboot the TV or just exit the service menu (if, for example, no changes have been made)",
|
||||
FieldType = FieldType.DropDown,
|
||||
Values = exitServiceMenuTypes,
|
||||
Value = ExitServiceMenuType.Exit
|
||||
};
|
||||
|
||||
if (!MessageForms.ShowDialog($"Exit Service Menu", [exitServiceMenuTypeField], okButtonText: "Next >").Any())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
await ExecutePresetWithProgressAsync(rebootPreset, "Final Step: rebooting TV...");
|
||||
var task = exitServiceMenuTypeField.ValueAsEnum<ExitServiceMenuType>() switch
|
||||
{
|
||||
ExitServiceMenuType.Exit => ExecutePresetWithProgressAsync(exitPreset, "Final Step: exiting service menu..."),
|
||||
ExitServiceMenuType.Reboot => ExecutePresetWithProgressAsync(rebootPreset, "Final Step: rebooting TV...")
|
||||
};
|
||||
|
||||
await task;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -156,7 +156,7 @@ namespace ColorControl.Services.Samsung
|
||||
{
|
||||
case PowerOnOffState.StandBy:
|
||||
{
|
||||
_ = ExecutePresetsForEvent(PresetTriggerType.Standby).ConfigureAwait(true);
|
||||
//_ = ExecutePresetsForEvent(PresetTriggerType.Standby).ConfigureAwait(true);
|
||||
|
||||
var devices = Devices.Where(d => d.Options.PowerOffOnStandby);
|
||||
PowerOffDevices(devices, PowerOnOffState.StandBy);
|
||||
@@ -415,6 +415,7 @@ namespace ColorControl.Services.Samsung
|
||||
}
|
||||
|
||||
Logger.Debug("Powering off tv(s)...");
|
||||
|
||||
var tasks = new List<Task>();
|
||||
foreach (var device in devices)
|
||||
{
|
||||
@@ -425,15 +426,28 @@ namespace ColorControl.Services.Samsung
|
||||
|
||||
if (state == PowerOnOffState.StandBy)
|
||||
{
|
||||
var standByScript = Path.Combine(Program.DataDir, "StandByScript.bat");
|
||||
if (File.Exists(standByScript))
|
||||
var task = Task.Run(() =>
|
||||
{
|
||||
_winApiAdminService.StartProcess(standByScript, hidden: true, wait: true);
|
||||
}
|
||||
var standByScript = Path.Combine(Program.DataDir, "StandByScript.bat");
|
||||
if (File.Exists(standByScript))
|
||||
{
|
||||
_winApiAdminService.StartProcess(standByScript, hidden: true, wait: true, useShellExecute: false);
|
||||
}
|
||||
});
|
||||
|
||||
tasks.Add(task);
|
||||
}
|
||||
|
||||
// We can't use async here because we need to stay on the main thread...
|
||||
var _ = Task.WhenAll(tasks.ToArray()).ConfigureAwait(true);
|
||||
var i = 0;
|
||||
while (tasks.Any(t => t.Status < TaskStatus.WaitingForChildrenToComplete) && i < 200)
|
||||
{
|
||||
Thread.Sleep(10);
|
||||
System.Windows.Forms.Application.DoEvents();
|
||||
i++;
|
||||
}
|
||||
|
||||
//var _ = Task.WhenAll(tasks.ToArray());
|
||||
|
||||
Logger.Debug("Done powering off tv(s)");
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace nspector.Common.CustomSettings
|
||||
{
|
||||
var settings = XMLHelper<CustomSettingNames>.DeserializeFromXMLFile(filename);
|
||||
|
||||
var interpolatedSettings = settings.Settings.Where(s => s.SettingValues.Count == 2 && s.SettingValues[1].SettingValue <= 1200 && (s.SettingValues[1].SettingValue - s.SettingValues[0].SettingValue) >= 50).ToList();
|
||||
var interpolatedSettings = settings.Settings.Where(s => s.SettingValues.Count == 2 && s.SettingValues[1].SettingValue <= 2000 && (s.SettingValues[1].SettingValue - s.SettingValues[0].SettingValue) >= 50).ToList();
|
||||
|
||||
foreach (var setting in interpolatedSettings)
|
||||
{
|
||||
|
||||
@@ -7718,8 +7718,8 @@
|
||||
<HexValue>0x00000190</HexValue>
|
||||
</CustomSettingValue>
|
||||
<CustomSettingValue>
|
||||
<UserfriendlyName>1200</UserfriendlyName>
|
||||
<HexValue>0x000004B0</HexValue>
|
||||
<UserfriendlyName>1500</UserfriendlyName>
|
||||
<HexValue>0x000005DC</HexValue>
|
||||
</CustomSettingValue>
|
||||
</SettingValues>
|
||||
<SettingMasks />
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
namespace ColorControl.Shared.Contracts
|
||||
|
||||
namespace ColorControl.Shared.Contracts
|
||||
{
|
||||
public enum ElevationMethod
|
||||
{
|
||||
@@ -10,6 +11,7 @@
|
||||
|
||||
public class Config
|
||||
{
|
||||
public bool AutoStart { get; set; }
|
||||
public bool StartMinimized { get; set; }
|
||||
public bool MinimizeOnClose { get; set; }
|
||||
public bool MinimizeToTray { get; set; }
|
||||
@@ -45,6 +47,7 @@
|
||||
|
||||
public Config()
|
||||
{
|
||||
AutoStart = false;
|
||||
LogLevel = "DEBUG";
|
||||
DisplaySettingsDelay = 1000;
|
||||
ScreenSaverShortcut = string.Empty;
|
||||
@@ -65,5 +68,24 @@
|
||||
GamePresetsSortState = new ListViewSortState();
|
||||
Modules = new List<Module>();
|
||||
}
|
||||
|
||||
public Config(Config config) : this()
|
||||
{
|
||||
Update(config);
|
||||
}
|
||||
|
||||
public void Update(Config config)
|
||||
{
|
||||
AutoStart = config.AutoStart;
|
||||
StartMinimized = config.StartMinimized;
|
||||
MinimizeOnClose = config.MinimizeOnClose;
|
||||
MinimizeToTray = config.MinimizeToTray;
|
||||
CheckForUpdates = config.CheckForUpdates;
|
||||
AutoInstallUpdates = config.AutoInstallUpdates;
|
||||
UseDarkMode = config.UseDarkMode;
|
||||
ScreenSaverShortcut = config.ScreenSaverShortcut;
|
||||
FixChromeFonts = config.FixChromeFonts;
|
||||
UseGdiScaling = config.UseGdiScaling;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@ public class DisplayConfig
|
||||
public Rational RefreshRate { get; set; }
|
||||
public DisplayConfigScaling Scaling { get; set; }
|
||||
public DisplayConfigRotation Rotation { get; set; }
|
||||
public bool? IsPrimary { get; set; }
|
||||
|
||||
public DisplayConfig()
|
||||
{
|
||||
|
||||
@@ -136,6 +136,8 @@ namespace ColorControl.Shared.Native
|
||||
config.Scaling = pathInfo.targetInfo.scaling;
|
||||
config.Rotation = pathInfo.targetInfo.rotation;
|
||||
|
||||
config.IsPrimary = sourceMode.sourceMode.position.x == 0 && sourceMode.sourceMode.position.y == 0;
|
||||
|
||||
return (default(DisplayConfigModeInfo), true);
|
||||
}, displayName
|
||||
);
|
||||
@@ -215,6 +217,39 @@ namespace ColorControl.Shared.Native
|
||||
}
|
||||
//pathsArray[pathIndex].targetInfo.refreshRate = new DisplayConfigRational { numerator = displayConfig.RefreshRate.Numerator, denominator = displayConfig.RefreshRate.Denominator };
|
||||
|
||||
var currentX = modesArray[sourceIndex].sourceMode.position.x;
|
||||
var currentY = modesArray[sourceIndex].sourceMode.position.y;
|
||||
if (displayConfig.IsPrimary == true && (currentX != 0 || currentY != 0))
|
||||
{
|
||||
var shiftX = -currentX;
|
||||
var shiftY = -currentY;
|
||||
isModeChangeNeeded = true;
|
||||
|
||||
for (var i = 0; i < modesArray.Length; i++)
|
||||
{
|
||||
if (modesArray[i].infoType != DisplayConfigModeInfoType.Source)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i == sourceIndex)
|
||||
{
|
||||
modesArray[sourceIndex].sourceMode.position.x = 0;
|
||||
modesArray[sourceIndex].sourceMode.position.y = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (modesArray[i].sourceMode.position.x < currentX || modesArray[i].sourceMode.position.x > currentX)
|
||||
{
|
||||
modesArray[i].sourceMode.position.x += shiftX;
|
||||
}
|
||||
if (modesArray[i].sourceMode.position.y < currentY || modesArray[i].sourceMode.position.y > currentY)
|
||||
{
|
||||
modesArray[i].sourceMode.position.y += shiftY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isModeChangeNeeded)
|
||||
{
|
||||
var flags = SdcFlags.Apply | SdcFlags.UseSuppliedDisplayConfig | SdcFlags.AllowChanges;
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
using ColorControl.Shared.Contracts;
|
||||
|
||||
namespace ColorControl.Shared.Services;
|
||||
|
||||
public class OptionsService
|
||||
{
|
||||
//private readonly GlobalContext _globalContext;
|
||||
|
||||
private readonly Config _config;
|
||||
|
||||
public OptionsService()
|
||||
{
|
||||
//_globalContext = globalContext;
|
||||
|
||||
_config = new Config();
|
||||
}
|
||||
|
||||
public Config GetConfig()
|
||||
{
|
||||
return new Config(_config);
|
||||
}
|
||||
|
||||
public void SetConfig(Config config)
|
||||
{
|
||||
_config.Update(config);
|
||||
}
|
||||
}
|
||||
@@ -112,16 +112,24 @@ namespace ColorControl.Shared.Services
|
||||
}
|
||||
}
|
||||
|
||||
public Process StartProcess(string fileName, string arguments = null, bool hidden = false, bool wait = false, bool setWorkingDir = false, bool elevate = false, uint affinityMask = 0, uint priorityClass = 0)
|
||||
public Process StartProcess(string fileName, string arguments = null, bool hidden = false, bool wait = false, bool setWorkingDir = false, bool elevate = false, uint affinityMask = 0, uint priorityClass = 0, bool? useShellExecute = null)
|
||||
{
|
||||
var process = Process.Start(new ProcessStartInfo(fileName, arguments)
|
||||
{
|
||||
Verb = elevate ? "runas" : string.Empty, // indicates to elevate privileges
|
||||
UseShellExecute = true,
|
||||
UseShellExecute = useShellExecute.HasValue ? useShellExecute.Value : !hidden || !(fileName.EndsWith(".exe", StringComparison.OrdinalIgnoreCase) || fileName.EndsWith(".bat", StringComparison.OrdinalIgnoreCase)),
|
||||
WindowStyle = hidden ? ProcessWindowStyle.Hidden : ProcessWindowStyle.Normal,
|
||||
WorkingDirectory = setWorkingDir ? Path.GetDirectoryName(fileName) : null
|
||||
});
|
||||
|
||||
if (process == null)
|
||||
{
|
||||
Logger.Debug($"Process {fileName} could not be started: null returned");
|
||||
return null;
|
||||
}
|
||||
|
||||
Logger.Debug($"Started process {fileName} with process-id {process.Id}: has exited {process.HasExited}");
|
||||
|
||||
if (affinityMask > 0)
|
||||
{
|
||||
SetProcessAffinity(process.Id, affinityMask);
|
||||
|
||||
Reference in new issue
Block a user