Training + Liste erneuert

This commit is contained in:
2024-11-27 20:30:52 +01:00
parent 2c7fbac29c
commit ab021cb4c2
6 changed files with 274 additions and 51 deletions

View File

@@ -1,24 +1,46 @@
<!-- src/app/training.component.html -->
<div class="mt-10">
<h2 class="text-2xl font-bold mb-4">Training: {{ deck.name }}</h2>
<div class="bg-white shadow rounded-lg p-6 flex flex-col items-center">
<img [src]="currentImage" alt="Vokabelbild" class="max-h-[50vh] object-contain mb-4">
<div *ngIf="showTextFlag" class="bg-black bg-opacity-50 text-white text-lg p-2 rounded mb-4">
<!-- {{ currentImage?.text }} -->
</div>
<div class="flex space-x-4">
<button (click)="showText()" class="bg-green-500 text-white py-2 px-4 rounded hover:bg-green-600" [disabled]="showTextFlag">
Anzeigen
</button>
<button (click)="markKnown()" class="bg-blue-500 text-white py-2 px-4 rounded hover:bg-blue-600">
Gewusst
</button>
<button (click)="markUnknown()" class="bg-red-500 text-white py-2 px-4 rounded hover:bg-red-600">
Nicht gewusst
</button>
</div>
<p class="mt-4">{{ progress }}</p>
<button (click)="closeTraining()" class="mt-4 text-gray-500 hover:text-gray-700 underline">Training beenden</button>
<h2 class="text-2xl font-bold mb-4">Training: {{ deck.name }}</h2>
<div class="bg-white shadow rounded-lg p-6 flex flex-col items-center">
<canvas #canvas class="mb-4 border max-h-[50vh]"></canvas>
<div class="flex space-x-4 mb-4">
<!-- Anzeigen Button -->
<button
(click)="showText()"
class="bg-green-500 disabled:bg-green-200 text-white py-2 px-4 rounded hover:bg-green-600"
[disabled]="isShowingBox || currentBoxIndex >= boxes.length"
>
Anzeigen
</button>
<!-- Gewusst Button -->
<button
(click)="markKnown()"
class="bg-blue-500 disabled:bg-blue-200 text-white py-2 px-4 rounded hover:bg-blue-600"
[disabled]="!isShowingBox || currentBoxIndex >= boxes.length"
>
Gewusst
</button>
<!-- Nicht gewusst Button -->
<button
(click)="markUnknown()"
class="bg-red-500 disabled:bg-red-200 text-white py-2 px-4 rounded hover:bg-red-600"
[disabled]="!isShowingBox || currentBoxIndex >= boxes.length"
>
Nicht gewusst
</button>
</div>
<p class="mt-2">{{ progress }}</p>
<p class="mt-2">Gewusst: {{ knownCount }} | Nicht gewusst: {{ unknownCount }}</p>
<button
(click)="closeTraining()"
class="mt-4 text-gray-500 hover:text-gray-700 underline"
>
Training beenden
</button>
</div>
</div>

View File

@@ -1,7 +1,9 @@
// src/app/training.component.ts
import { Component, Input, Output, EventEmitter } from '@angular/core';
import { Deck, DeckImage } from '../deck.service';
import { Component, Input, Output, EventEmitter, OnInit, ViewChild, ElementRef } from '@angular/core';
import { Deck, DeckImage, DeckService, Box } from '../deck.service';
import { CommonModule } from '@angular/common';
import { switchMap } from 'rxjs/operators';
import { forkJoin } from 'rxjs';
@Component({
selector: 'app-training',
@@ -9,54 +11,148 @@ import { CommonModule } from '@angular/common';
standalone: true,
imports: [CommonModule]
})
export class TrainingComponent {
export class TrainingComponent implements OnInit {
@Input() deck!: Deck;
@Output() close = new EventEmitter<void>();
currentIndex: number = 0;
@ViewChild('canvas') canvasRef!: ElementRef<HTMLCanvasElement>;
currentImageIndex: number = 0;
currentImageData: DeckImage | null = null;
currentBoxIndex: number = 0;
boxes: Box[] = [];
boxRevealed: boolean[] = [];
knownCount: number = 0;
unknownCount: number = 0;
showTextFlag: boolean = false;
get currentImage(): string | null {
if (this.currentIndex < this.deck.images.length) {
return `/api/debug_image/${this.deck.images[this.currentIndex].name}`;
isShowingBox: boolean = false;
isTrainingFinished: boolean = false;
constructor(private deckService: DeckService) { }
ngOnInit(): void {
if (this.deck && this.deck.images.length > 0) {
this.loadImage(this.currentImageIndex);
} else {
alert('Kein Deck oder keine Bilder vorhanden.');
this.close.emit();
}
return null;
}
get progress(): string {
return `Fortschritt: ${this.currentIndex} / ${this.deck.images.length}`;
loadImage(imageIndex: number): void {
if (imageIndex >= this.deck.images.length) {
this.endTraining();
return;
}
const imageName = this.deck.images[imageIndex].name;
this.deckService.getImage(imageName).subscribe({
next: (imageData: DeckImage) => {
this.currentImageData = imageData;
this.boxes = imageData.boxes;
this.boxRevealed = new Array(this.boxes.length).fill(false);
this.currentBoxIndex = 0;
this.isShowingBox = false;
this.drawCanvas();
},
error: (err) => {
console.error('Fehler beim Laden des Bildes:', err);
alert('Fehler beim Laden des Bildes.');
this.close.emit();
}
});
}
drawCanvas(): void {
const canvas = this.canvasRef.nativeElement;
const ctx = canvas.getContext('2d');
if (!ctx || !this.currentImageData) return;
const img = new Image();
img.src = `/api/debug_image/${this.currentImageData.name}`;
img.onload = () => {
// Set canvas size to image size
canvas.width = img.width;
canvas.height = img.height;
// Draw image
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
// Draw boxes
this.boxes.forEach((box, index) => {
if (this.boxRevealed[index]) {
// Box ist bereits enthüllt, nichts zeichnen
return;
}
ctx.beginPath();
ctx.rect(box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1);
ctx.fillStyle = index === this.currentBoxIndex ? 'rgba(0, 255, 0, 0.99)' : 'rgba(255, 0, 0, 0.99)';
ctx.fill();
ctx.lineWidth = 2;
ctx.strokeStyle = 'black';
ctx.stroke();
});
};
img.onerror = () => {
console.error('Fehler beim Laden des Bildes für Canvas.');
alert('Fehler beim Laden des Bildes für Canvas.');
this.close.emit();
};
}
showText(): void {
this.showTextFlag = true;
if (this.currentBoxIndex >= this.boxes.length) return;
this.boxRevealed[this.currentBoxIndex] = true;
this.isShowingBox = true;
this.drawCanvas();
}
markKnown(): void {
this.knownCount++;
this.nextImage();
this.nextBox();
}
markUnknown(): void {
this.unknownCount++;
this.nextImage();
this.nextBox();
}
nextImage(): void {
this.currentIndex++;
this.showTextFlag = false;
if (this.currentIndex >= this.deck.images.length) {
this.endTraining();
nextBox(): void {
this.currentBoxIndex++;
this.isShowingBox = false;
if (this.currentBoxIndex >= this.boxes.length) {
// Alle Boxen für dieses Bild sind bearbeitet
this.nextImage();
} else {
// Aktualisiere die Farben der Boxen
this.drawCanvas();
}
}
nextImage(): void {
this.currentImageIndex++;
this.loadImage(this.currentImageIndex);
}
endTraining(): void {
this.isTrainingFinished = true;
alert(`Training beendet!\nGewusst: ${this.knownCount}\nNicht gewusst: ${this.unknownCount}`);
this.close.emit();
}
closeTraining(): void {
this.close.emit();
if (confirm('Möchtest du das Training wirklich beenden?')) {
this.close.emit();
}
}
get progress(): string {
return `Bild ${this.currentImageIndex + 1} von ${this.deck.images.length}`;
}
}