save peripherals in project file

This commit is contained in:
2024-12-20 17:18:57 +01:00
parent 17b5d39fc4
commit 9964ccef7e
19 changed files with 316 additions and 228 deletions

View File

@@ -9,29 +9,30 @@
import Show from './components/Show/Show.svelte';
import GeneralConsole from './components/Console/GeneralConsole.svelte';
import RoundIconButton from './components/General/RoundIconButton.svelte';
import { currentProject, needProjectSave, peripherals } from './stores';
import { showInformation, needProjectSave, availablePeripherals, savedPeripherals } from './stores';
import { SaveProject } from '../wailsjs/go/main/App.js';
import { construct_svelte_component } from 'svelte/internal';
import { EventsOn } from '../wailsjs/runtime'
import { GetPeripherals } from "../wailsjs/go/main/App";
import { CreateProject, GetPeripherals } from "../wailsjs/go/main/App";
import { WindowSetTitle } from "../wailsjs/runtime/runtime"
// When the list of hardware changed, update the store
// Handle the event when a new peripheral is detected
EventsOn('PERIPHERAL_ARRIVAL', function(peripheralInfo){
console.log("Hardware has been added to the system");
console.log(peripheralInfo)
$peripherals = [...$peripherals, peripheralInfo];
$availablePeripherals = [...$availablePeripherals, peripheralInfo];
})
// Handle the event when a peripheral is removed from the system
EventsOn('PERIPHERAL_REMOVAL', function(peripheralInfo){
console.log("Hardware has been removed from the system");
console.log(peripheralInfo)
$peripherals = $peripherals.filter(item => JSON.stringify(item) !== JSON.stringify(peripheralInfo))
console.log($peripherals)
// $peripherals = devicesList
// console.log(devicesList)
$availablePeripherals = $availablePeripherals.filter(item => JSON.stringify(item) !== JSON.stringify(peripheralInfo))
})
// Set the window title
$: {
WindowSetTitle("DMXConnect - " + $showInformation.Name + ($needProjectSave ? " (unsaved)" : ""))
}
let selectedMenu = "settings"
// When the navigation menu changed, update the selected menu
function onNavigationChanged(event){
@@ -40,44 +41,41 @@
// Save the project
function saveProject(){
SaveProject($currentProject).then((saveFile) => {
console.log($currentProject)
$currentProject.SaveFile = saveFile
SaveProject().then((filePath) => {
needProjectSave.set(false)
console.log("Project has been saved")
console.log("Project has been saved to " + filePath)
}).catch((error) => {
console.error(`Unable to save the project: ${error}`)
})
}
function formatDate(date) {
const pad = (number) => number.toString().padStart(2, '0');
const year = date.getFullYear();
const month = pad(date.getMonth() + 1); // Les mois commencent à 0
const day = pad(date.getDate());
const hours = pad(date.getHours());
const minutes = pad(date.getMinutes());
return `${year}-${month}-${day}T${hours}:${minutes}`;
}
currentProject.set({
Name: "My new show",
Date: formatDate(new Date()),
Avatar: "appicon.png",
UniversesNumber: 1,
Comments: "Write your comments here",
SaveFile: "",
});
// Instanciate a new project
CreateProject().then((showInfo) => {
showInformation.set(showInfo)
$needProjectSave = true
})
// Request the list of peripherals
// TODO: Handle the error here
GetPeripherals()
// Handle window shortcuts
document.addEventListener('keydown', function(event) {
// Check the CTRL+S keys
if ((event.ctrlKey || event.metaKey) && event.key === 's') {
// Avoid the natural behaviour
event.preventDefault();
// Save the current project
saveProject()
}
});
</script>
<header>
<NavigationBar on:navigationChanged="{onNavigationChanged}"/>
{#if $needProjectSave}
<RoundIconButton on:click={saveProject} icon="bx-save" width="2.5em" tooltip={$_("saveButtonTooltip")}></RoundIconButton>
<RoundIconButton on:mouseup={saveProject} icon="bx-save" width="2.5em" tooltip={$_("saveButtonTooltip")}></RoundIconButton>
{/if}
<Clock/>
</header>

View File

@@ -15,21 +15,27 @@
const dispatch = createEventDispatcher();
function handleInput(event){
value = event.target.value
dispatch('input', value)
function handleInput(){
dispatch('input')
}
function handleBlur(event){
dispatch('blur', event)
}
function handleDblClick(){
dispatch('dblclick')
}
</script>
<div style="width: {width}; height: {height};">
<p style="color: {$colors.white};">{label}</p>
<!-- Handle the textarea input -->
{#if type === 'large'}
<textarea style="background-color: {$colors.second}; color: {$colors.white};" placeholder={placeholder} value={value} on:input={handleInput}/>
<textarea style="background-color: {$colors.second}; color: {$colors.white};" placeholder={placeholder} value={value} on:dblclick={handleDblClick} on:input={handleInput} on:blur={handleBlur}/>
<!-- Handle the simple inputs -->
{:else}
<input style="background-color: {$colors.second}; color: {$colors.white};" type={type} min={min} max={max} src={src} alt={alt} value={value} placeholder={placeholder} on:input={handleInput}/>
<input style="background-color: {$colors.second}; color: {$colors.white};" type={type} min={min} max={max} src={src} alt={alt} value={value} placeholder={placeholder} on:dblclick={handleDblClick} on:input={handleInput} on:blur={handleBlur}/>
{/if}
</div>
@@ -48,14 +54,14 @@
}
input::selection {
background: #0F4C75; /* Couleur de fond de la sélection */
color: #FFFFFF; /* Couleur du texte de la sélection */
background: var(--first-color); /* Couleur de fond de la sélection */
color: var(--white-color); /* Couleur du texte de la sélection */
}
/* Pour Firefox */
input::-moz-selection {
background: #0F4C75; /* Couleur de fond de la sélection */
color: #FFFFFF; /* Couleur du texte de la sélection */
background: var(--first-color); /* Couleur de fond de la sélection */
color: var(--white-color); /* Couleur du texte de la sélection */
}
input:focus {
outline: 1px solid #BBE1FA;
@@ -69,14 +75,14 @@
}
textarea::selection {
background: #0F4C75; /* Couleur de fond de la sélection */
color: #FFFFFF; /* Couleur du texte de la sélection */
background: var(--first-color); /* Couleur de fond de la sélection */
color: var(--white-color); /* Couleur du texte de la sélection */
}
/* Pour Firefox */
textarea::-moz-selection {
background: #0F4C75; /* Couleur de fond de la sélection */
color: #FFFFFF; /* Couleur du texte de la sélection */
background: var(--first-color); /* Couleur de fond de la sélection */
color: var(--white-color); /* Couleur du texte de la sélection */
}
textarea:focus {
outline: 1px solid #BBE1FA;

View File

@@ -48,8 +48,11 @@
// Emit a click event when the button is clicked
const dispatch = createEventDispatcher();
function emitClick() {
dispatch('click');
function emitMouseDown() {
dispatch('mousedown');
}
function emitMouseUp() {
dispatch('mouseup');
}
let tooltipPosition = {top: 0, left: 0}
@@ -71,7 +74,8 @@
<div class="container">
<button bind:this={buttonRef}
style="width:{width}; height:{width}; border-radius:{width}; background-color:{background}; color:{foreground};"
on:mousedown={emitClick}
on:mousedown={emitMouseDown}
on:mouseup={emitMouseUp}
on:mouseenter={() => { toggleTooltip(true) }}
on:mouseleave={() => { toggleTooltip(false) }}>
<i class='bx {icon}' style="font-size:100%;"></i>

View File

@@ -29,10 +29,15 @@
dispatch('click');
}
function handleBlur(){
dispatch('blur')
}
</script>
<div class="container">
<button bind:this={buttonRef}
on:blur={handleBlur}
on:mousedown={emitClick}
on:mouseenter={() => { toggleTooltip(true) }}
on:mouseleave={() => { toggleTooltip(false) }}

View File

@@ -32,7 +32,6 @@
<style>
.headerContainer{
cursor: pointer;
margin:0;
border-radius: 0.5em;
}

View File

@@ -25,16 +25,17 @@
dispatch('add')
}
let showOptions = false
function click(){
showOptions = !showOptions
dispatch('click')
}
function dblclick(){
dispatch('dblclick')
}
</script>
<div class="card">
<div class="card" on:dblclick={dblclick}>
<div class="profile" on:mousedown={click} style="color: {disconnected ? $colors.first : $colors.white};">
<div>
<p>{#if disconnected}<i class='bx bx-no-signal' style="font-size:100%; color: var(--nok-color);"></i> {/if}{title}</p>
@@ -53,9 +54,6 @@
<InfoButton style="margin: 0.2em;" background={ signalized ? $colors.orange : $colors.first } icon='bx-pulse' hide={!signalizable}/>
</div>
</div>
<div class="options" style="display: {showOptions ? "block" : "none"};">
<Input label={$_("projectCommentsLabel")} type='large' width='100%'/>
</div>
</div>
@@ -83,17 +81,6 @@
.actions {
margin-left: 0.2em;
}
.options {
color: var(--first-color);
padding: 0.2em;
margin-top: 0.2em;
position: absolute;
display:block;
border-radius: 0.5em;
max-width: 50;
background-color: var(--fourth-color);
text-align: left;
}
p{
margin: 0;
}

View File

@@ -2,8 +2,8 @@
import DeviceCard from "./DeviceCard.svelte";
import Tab from "../General/Tab.svelte";
import { _ } from 'svelte-i18n'
import { peripherals } from "../../stores";
import { ConnectFTDI, ActivateFTDI, DeactivateFTDI, DisconnectFTDI, SetDeviceFTDI } from "../../../wailsjs/go/main/App";
import { availablePeripherals, needProjectSave, savedPeripherals } from "../../stores";
import { RemovePeripheral, ConnectFTDI, ActivateFTDI, DeactivateFTDI, DisconnectFTDI, SetDeviceFTDI, AddPeripheral } from "../../../wailsjs/go/main/App";
function ftdiConnect(){
ConnectFTDI().then(() =>
@@ -47,45 +47,60 @@
})
}
// Add the peripheral to the project
function addPeripheral(peripheral){
// Add the peripheral to the project (backend)
AddPeripheral(peripheral.ProtocolName, peripheral.SerialNumber).then(() => {
$needProjectSave = true
$savedPeripherals = [...$savedPeripherals, peripheral];
}).catch((error) => {
console.log("Unable to add the peripheral to the project: " + error)
})
}
// Remove the peripheral from the project
function removePeripheral(peripheral) {
// Delete the peripheral from the project (backend)
RemovePeripheral(peripheral.ProtocolName, peripheral.SerialNumber).then(() => {
$needProjectSave = true
$savedPeripherals = $savedPeripherals.filter(item => JSON.stringify(item) !== JSON.stringify(peripheral))
}).catch((error) => {
console.log("Unable to remove the peripheral from the project: " + error)
})
}
</script>
<div class="hardware">
<div style="padding: 0.5em;">
<p style="margin-bottom: 1em;">Available devices</p>
<p style="margin-bottom: 1em;">Available peripherals</p>
<div class="availableHardware">
<p style="color: var(--first-color);"><i class='bx bxs-plug'></i> Detected</p>
{#each $peripherals as peripheral}
<DeviceCard title={peripheral.Name == "" ? "Please wait..." : peripheral.Name} type={peripheral.ProtocolName} location={peripheral.Location ? peripheral.Location : ""} line1={peripheral.SerialNumber ? "S/N: " + peripheral.SerialNumber : ""} addable/>
{/each}
{#each $availablePeripherals as peripheral}
<DeviceCard on:add={() => addPeripheral(peripheral)} on:dblclick={() => addPeripheral(peripheral)}
title={peripheral.Name == "" ? "Please wait..." : peripheral.Name} type={peripheral.ProtocolName} location={peripheral.Location ? peripheral.Location : ""} line1={peripheral.SerialNumber ? "S/N: " + peripheral.SerialNumber : ""} addable={!peripheral.isAdded}/>
{/each}
<p style="color: var(--first-color);"><i class='bx bxs-network-chart' ></i> Others</p>
<DeviceCard on:click={() => console.log("Edit the OS2L hardware")} title="OS2L device" type="OS2L" line1="Add to configure" addable on:delete={() => console.log("Delete the OS2L device")}/>
<DeviceCard on:click={() => console.log("Edit the OSC hardware")} title="OSC device" type="OSC" line1="Add to configure" addable on:delete={() => console.log("Delete the OSC device")}/>
<DeviceCard on:click={() => console.log("Edit the ArtNet hardware")} title="ArtNet device" type="ArtNet" line1="Add to configure" addable on:delete={() => console.log("Delete the ArtNet device")}/>
<DeviceCard on:click={() => console.log("Edit the ArtNet hardware")} title="ArtNet device" type="ArtNet" line1="Add to configure" addable on:delete={() => console.log("Delete the ArtNet device")}/>
<DeviceCard on:click={() => console.log("Edit the ArtNet hardware")} title="ArtNet device" type="ArtNet" line1="Add to configure" addable on:delete={() => console.log("Delete the ArtNet device")}/>
<DeviceCard on:click={() => console.log("Edit the ArtNet hardware")} title="ArtNet device" type="ArtNet" line1="Add to configure" addable on:delete={() => console.log("Delete the ArtNet device")}/>
<DeviceCard on:click={() => console.log("Edit the ArtNet hardware")} title="ArtNet device" type="ArtNet" line1="Add to configure" addable on:delete={() => console.log("Delete the ArtNet device")}/>
<DeviceCard on:click={() => console.log("Edit the ArtNet hardware")} title="ArtNet device" type="ArtNet" line1="Add to configure" addable on:delete={() => console.log("Delete the ArtNet device")}/>
<DeviceCard on:click={() => console.log("Edit the ArtNet hardware")} title="ArtNet device" type="ArtNet" line1="Add to configure" addable on:delete={() => console.log("Delete the ArtNet device")}/>
<DeviceCard on:click={() => console.log("Edit the ArtNet hardware")} title="ArtNet device" type="ArtNet" line1="Add to configure" addable on:delete={() => console.log("Delete the ArtNet device")}/>
<DeviceCard on:click={() => console.log("Edit the ArtNet hardware")} title="ArtNet device" type="ArtNet" line1="Add to configure" addable on:delete={() => console.log("Delete the ArtNet device")}/>
<DeviceCard on:click={() => console.log("Edit the ArtNet hardware")} title="ArtNet device" type="ArtNet" line1="Add to configure" addable on:delete={() => console.log("Delete the ArtNet device")}/>
<DeviceCard on:click={() => console.log("Edit the ArtNet hardware")} title="ArtNet device" type="ArtNet" line1="Add to configure" addable on:delete={() => console.log("Delete the ArtNet device")}/>
<DeviceCard on:click={() => console.log("Edit the ArtNet hardware")} title="ArtNet device" type="ArtNet" line1="Add to configure" addable on:delete={() => console.log("Delete the ArtNet device")}/>
<DeviceCard disconnected on:click={() => console.log("Edit the OS2L hardware")} title="OS2L device" type="OS2L" line1="Add to configure" addable on:add={() => console.log("Add an OS2L device")}/>
<DeviceCard disconnected on:click={() => console.log("Edit the OSC hardware")} title="OSC device" type="OSC" line1="Add to configure" addable on:add={() => console.log("Add an OSC device")}/>
<DeviceCard disconnected on:click={() => console.log("Edit the ArtNet hardware")} title="ArtNet device" type="ArtNet" line1="Add to configure" addable on:add={() => console.log("Add an ArtNet device")}/>
</div>
</div>
<div style="padding: 0.5em; flex:2; width:100%;">
<p style="margin-bottom: 1em;">Project devices</p>
<p style="margin-bottom: 1em;">Project peripherals</p>
<div class="configuredHardware">
<DeviceCard disconnected on:click={() => console.log("Edit the VDJ hardware")} title="Virtual DJ" type="OS2L" location="192.168.1.53" line1="Please update your OS2L client" removable signalizable on:delete={() => console.log("Delete the Virtual DJ device")}/>
<DeviceCard disconnected title="Pioneer DDJ-FLX4" type="MIDI" location="COM14" line1="Version: 0-alpha-13.15" removable signalizable/>
<DeviceCard title="Platformia LM730" type="OSC" location="192.168.1.418" line1="Please update your OSC client" removable signalizable/>
{#if $savedPeripherals.length == 0}
<i>Add peripherals from the left panel</i>
{/if}
{#each $savedPeripherals as peripheral}
<DeviceCard on:delete={() => removePeripheral(peripheral)} on:dblclick={() => removePeripheral(peripheral)}
title={peripheral.Name == "" ? "Please wait..." : peripheral.Name} type={peripheral.ProtocolName} location={peripheral.Location ? peripheral.Location : ""} line1={peripheral.SerialNumber ? "S/N: " + peripheral.SerialNumber : ""} removable signalizable/>
{/each}
</div>
<p style="margin-bottom: 1em;">Device settings</p>
<p style="margin-bottom: 1em;">Peripheral settings</p>
<div>
<p><i>Select a device to edit its settings</i></p>
<p><i>Select a peripheral to edit its settings</i></p>
<button on:click={ftdiConnect}>Connect FTDI 0</button>
<button on:click={ftdiActivate}>Activate FTDI 0</button>
<div class="slidecontainer">

View File

@@ -1,6 +1,7 @@
<script lang=ts>
import { ChooseAvatarPath } from '../../../wailsjs/go/main/App.js';
import { currentProject } from '../../stores.js';
import { set_data_contenteditable } from 'svelte/internal';
import { ChooseAvatarPath, UpdateShowInfo } from '../../../wailsjs/go/main/App.js';
import { showInformation, needProjectSave } from '../../stores.js';
import Input from "../General/Input.svelte";
import RoundedButton from '../General/RoundedButton.svelte';
import { _ } from 'svelte-i18n'
@@ -8,41 +9,42 @@
// Choose the avatar path
function chooseAvatar(){
ChooseAvatarPath().then((avatarPath) => {
console.log(`Avatar path is ${avatarPath}`)
$currentProject.Avatar = avatarPath
$showInformation["Avatar"] = avatarPath
UpdateShowInfo($showInformation).then(()=> {
$needProjectSave = true
})
}).catch((error) => {
console.error(`An error occured: ${error}`)
})
}
function updateUniverses(event) {
currentProject.update(obj => {
return {
...obj,
UniversesNumber: parseInt(event.detail, 10) // Conversion en entier
};
});
function validate(field, value){
$showInformation[field] = value
console.log($showInformation)
UpdateShowInfo($showInformation).then(()=> {
$needProjectSave = true
})
}
</script>
<div class='flexSettings'>
<div>
<Input bind:value={$currentProject.Name} label={$_("projectShowNameLabel")} type='text'/>
<Input bind:value={$currentProject.Date} label={$_("projectShowDateLabel")} type='datetime-local'/>
<Input bind:value={$currentProject.UniversesNumber} on:input={updateUniverses} label={$_("projectUniversesLabel")} type='number' min=1 max=10/>
<Input on:blur={(event) => validate("Name", event.detail.target.value)} label={$_("projectShowNameLabel")} type='text' value={$showInformation.Name}/>
<Input on:blur={(event) => validate("Date", event.detail.target.value)} label={$_("projectShowDateLabel")} type='datetime-local' value={$showInformation.Date}/>
</div>
<div>
<Input bind:src={$currentProject.Avatar} label={$_("projectAvatarLabel")} type='image' alt={$_("projectAvatarLabel")} width='11em'/>
<RoundedButton on:click={chooseAvatar} style='display:block;' tooltip={$_("projectAvatarTooltip")} text={$_("projectLoadAvatarButton")} icon='bxs-image' active/>
</div>
<div>
<Input bind:value={$currentProject.Comments} label={$_("projectCommentsLabel")} type='large' width='100%'/>
<Input on:dblclick={chooseAvatar} label={$_("projectAvatarLabel")} type='image' alt={$_("projectAvatarLabel")} width='11em' src={$showInformation.Avatar}/>
</div>
</div>
<div>
<Input on:blur={(event) => validate("Comments", event.detail.target.value)} label={$_("projectCommentsLabel")} type='large' width='100%' value={$showInformation.Comments}/>
</div>
<style>
.flexSettings{
display: flex;
flex-direction: column;
flex-wrap: wrap;
width: 100%;
justify-content: space-between;
}
</style>

View File

@@ -1,11 +1,11 @@
<script lang=ts>
import { projectsList, currentProject, needProjectSave } from '../../stores.js';
import { projectsList, showInformation, needProjectSave, savedPeripherals } from '../../stores.js';
import RoundedButton from "../General/RoundedButton.svelte";
import ProjectPropertiesContent from "./ProjectPropertiesContent.svelte";
import DropdownList from "../General/DropdownList.svelte";
import InputsOutputsContent from "./InputsOutputsContent.svelte";
import Tab from "../General/Tab.svelte";
import { GetProjects, GetProjectInfo } from "../../../wailsjs/go/main/App";
import { CreateProject, GetProjects, GetProjectInfo } from "../../../wailsjs/go/main/App";
import { _ } from 'svelte-i18n'
import {colors} from '../../stores.js';
@@ -14,14 +14,12 @@
{ title: $_("projectInputOutputTab"), icon: 'bxs-plug', tooltip: $_("projectInputOutputTooltip"), component: InputsOutputsContent },
];
// Refresh the projects list
let choices = new Map()
function loadProjectsList(){
GetProjects().then((projects) => {
choices = new Map(projects.map(item => [item.ShowInfo.SaveFile, item.ShowInfo.Name]));
$projectsList = projects
console.log(projectsList)
choices = new Map(projects.map(item => [item.Save, item.Name]));
$projectsList = projects
}).catch((error) => {
console.error(`Unable to get the projects list: ${error}`)
})
@@ -31,8 +29,10 @@
let selectedOption = event.detail.key
// Open the selected project
GetProjectInfo(selectedOption).then((projectInfo) => {
console.log(projectInfo)
console.log("Project opened")
$currentProject = projectInfo
$showInformation = projectInfo.ShowInfo
$savedPeripherals = projectInfo.PeripheralsInfo
needProjectSave.set(false)
}).catch((error) => {
console.error(`Unable to open the project: ${error}`)
@@ -40,24 +40,12 @@
}
function initializeNewProject(){
currentProject.set({
Name: "My new show",
Date: formatDate(new Date()),
Avatar: "appicon.png",
UniversesNumber: 1,
Comments: "Write your comments here",
SaveFile: "",
});
}
function formatDate(date) {
const pad = (number) => number.toString().padStart(2, '0');
const year = date.getFullYear();
const month = pad(date.getMonth() + 1); // Les mois commencent à 0
const day = pad(date.getDate());
const hours = pad(date.getHours());
const minutes = pad(date.getMinutes());
return `${year}-${month}-${day}T${hours}:${minutes}`;
// Instanciate a new project
CreateProject().then((showInfo) => {
$showInformation = showInfo
$savedPeripherals = []
$needProjectSave = true
})
}
</script>

View File

@@ -2,7 +2,7 @@ import App from './App.svelte';
import { WindowSetTitle } from "../wailsjs/runtime/runtime"
import {currentProject, needProjectSave} from './stores.js';
import {showInformation, needProjectSave} from './stores.js';
// Load dictionaries
import { addMessages, init } from 'svelte-i18n';
@@ -24,28 +24,4 @@ const app = new App({
target: document.body,
});
// Set the initial title
WindowSetTitle("DMXConnect")
// When the current project data is modified, pass it to unsaved and change the title
let title;
currentProject.subscribe(value => {
needProjectSave.set(true)
title = value.Name
});
// If the project need to be saved, show the information in the title
needProjectSave.subscribe(value => {
if (value) {
console.log(`<!> The current project need to be save`);
WindowSetTitle("DMXConnect - " + title + " (unsaved)")
} else {
WindowSetTitle("DMXConnect - " + title)
}
})
document.addEventListener("DOMContentLoaded", function() {
});
export default app;

View File

@@ -2,10 +2,10 @@ import { writable } from 'svelte/store';
// Projects management
export let projectsList = writable([])
export let needProjectSave = writable(true)
// Show settings
export let currentProject = writable({})
export let needProjectSave = writable(false)
export let showInformation = writable({})
// Application colors
export const colors = writable({
@@ -25,4 +25,5 @@ export const secondSize = writable("14px")
export const thirdSize = writable("20px")
// List of current hardware
export let peripherals = writable([])
export let availablePeripherals = writable([])
export let savedPeripherals = writable([])