Refactor particle management: remove secret key from file operations, add ParticleManagerComponent, update frame naming conventions, and enhance style and functionality.

This commit is contained in:
2026-01-04 05:22:04 +01:00
parent 63aa7fd550
commit 8a0843128c
12 changed files with 164 additions and 35 deletions
@@ -0,0 +1,39 @@
<div class="card-div">
<mat-card>
<mat-card-header>
<mat-card-title>
<span>Particle Manager</span>
</mat-card-title>
</mat-card-header>
<mat-card-content>
<br>
<div class="row">
<div class="column">
<mat-form-field appearance="outline" class="type-field">
<mat-label>Particle to download</mat-label>
<input type="text"
[(ngModel)]="selectedParticle"
placeholder="Name of particle to download"
matInput>
</mat-form-field>
<button mat-icon-button (click)="downloadParticle()">
<mat-icon>download</mat-icon>
</button>
</div>
<div class="row">
<mat-form-field appearance="outline" class="type-field">
<mat-label>Particle to upload</mat-label>
<input type="text"
disabled
[ngModel]="createdParticleName"
placeholder="Name of particle to upload"
matInput>
</mat-form-field>
<button mat-icon-button (click)="uploadParticle()">
<mat-icon>upload</mat-icon>
</button>
</div>
</div>
</mat-card-content>
</mat-card>
</div>
@@ -0,0 +1,6 @@
.card-div {
mat-card {
background-color: var(--color-primary);
color: var(--font-color);
}
}
@@ -0,0 +1,86 @@
import {Component, inject} from '@angular/core';
import {FormsModule} from '@angular/forms';
import {MatInput, MatLabel} from '@angular/material/input';
import {MatFormFieldModule} from '@angular/material/form-field';
import {MatCard, MatCardContent, MatCardHeader, MatCardTitle} from '@angular/material/card';
import {MatIconModule} from '@angular/material/icon';
import {MatButtonModule} from '@angular/material/button';
import {ParticlesService} from '@api';
import {ParticleManagerService} from '@pages/particles/services/particle-manager.service';
import {FrameManagerService} from '@pages/particles/services/frame-manager.service';
@Component({
selector: 'app-particle-manager',
imports: [
FormsModule,
MatFormFieldModule,
MatInput,
MatLabel,
MatCard,
MatCardContent,
MatCardHeader,
MatCardTitle,
MatIconModule,
MatButtonModule,
],
templateUrl: './particle-manager.component.html',
styleUrl: './particle-manager.component.scss'
})
export class ParticleManagerComponent {
private readonly particlesService = inject(ParticlesService)
private readonly particleManagerService = inject(ParticleManagerService)
private readonly frameManagerService = inject(FrameManagerService)
private selectedParticleName: string = '';
set selectedParticle(particle: string) {
this.selectedParticleName = particle;
}
get selectedParticle(): string {
return this.selectedParticleName;
}
get createdParticleName(): string {
return this.particleManagerService.getParticleData().particle_name;
}
protected downloadParticle() {
if (this.selectedParticleName === '') {
return;
}
this.particlesService
.downloadFile(this.selectedParticleName)
.subscribe({
next: data => {
data.text().then(text => {
if (text.startsWith('<')) {
console.error("Failed to download particle: Invalid file format")
return;
}
this.particleManagerService.loadParticleData(text)
this.frameManagerService.switchFrame(this.particleManagerService.getCurrentFrame())
})
},
error: () => {
console.error("Failed to download particle: Invalid file name")
},
}
)
}
protected uploadParticle() {
this.particlesService
.saveFile(this.createdParticleName, new Blob([this.particleManagerService.generateJson()], {type: 'application/json'}))
.subscribe({
next: () => {
console.log("Successfully uploaded particle")
},
error: () => {
console.error("Failed to upload particle")
}
})
}
}
@@ -26,6 +26,9 @@
</div>
</div>
<div class="flex side-column">
<app-particle-manager>
</app-particle-manager>
<app-frames>
<button mat-icon-button matTooltip="Copy JSON to clipboard" (click)="copyJson()">
<mat-icon>content_copy</mat-icon>
@@ -25,6 +25,7 @@ import {RenderContainerComponent} from './components/render-container/render-con
import {ParticlesService} from '@api';
import {MatTooltipModule} from '@angular/material/tooltip';
import {FullSizeComponent} from '@shared-components/full-size/full-size.component';
import {ParticleManagerComponent} from '@pages/particles/components/particle-manager/particle-manager.component';
@Component({
selector: 'app-particles',
@@ -47,7 +48,8 @@ import {FullSizeComponent} from '@shared-components/full-size/full-size.componen
FramesComponent,
RenderContainerComponent,
MatTooltipModule,
FullSizeComponent
FullSizeComponent,
ParticleManagerComponent
],
templateUrl: './particles.component.html',
styleUrl: './particles.component.scss'
@@ -1,5 +1,5 @@
import { Injectable } from '@angular/core';
import { ParticleManagerService } from './particle-manager.service';
import {inject, Injectable} from '@angular/core';
import {ParticleManagerService} from './particle-manager.service';
/**
* Service responsible for managing animation frames
@@ -8,15 +8,14 @@ import { ParticleManagerService } from './particle-manager.service';
providedIn: 'root'
})
export class FrameManagerService {
constructor(private particleManager: ParticleManagerService) {}
private readonly particleManager = inject(ParticleManagerService);
/**
* Adds a new frame
*/
addFrame(): void {
const frames = this.particleManager.getFrames();
const frameId = `frame${frames.length + 1}`;
const frameId = `frame-${frames.length}`;
frames.push(frameId);
this.particleManager.setFrames(frames);
@@ -39,7 +39,7 @@ export class IntersectionPlaneService {
* Creates the intersection plane and adds it to the scene
*/
createIntersectionPlane(): THREE.Mesh {
const planeGeometry = new THREE.PlaneGeometry(3, 3);
const planeGeometry = new THREE.PlaneGeometry(5, 5);
const planeMaterial = new THREE.MeshBasicMaterial({
color: 0x00AA00,
transparent: true,
@@ -27,11 +27,11 @@ export class ParticleManagerService {
random_offset: 0,
stationary: true,
frames: {
'frame1': []
'frame-0': []
}
};
private currentFrame: string = 'frame1';
private frames: string[] = ['frame1'];
private currentFrame: string = 'frame-0';
private frames: string[] = ['frame-0'];
private selectedColor: string = '#ff0000';
private selectedParticle: Particle = Particle.DUST;
private selectedSize: number = 1;
@@ -301,4 +301,10 @@ export class ParticleManagerService {
this.clearParticleVisuals();
this.renderFrameParticles(this.currentFrame);
}
public loadParticleData(data: string): void {
this.particleData = JSON.parse(data);
this.setCurrentFrame('frame-0');
this.frames = Object.keys(this.particleData.frames);
}
}