151 lines
4.9 KiB
PHP
151 lines
4.9 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
require_once __DIR__ . '/../vendor/autoload.php';
|
|
|
|
use PHPNative\Framework\Application;
|
|
use PHPNative\Ui\Widget\Button;
|
|
use PHPNative\Ui\Widget\Container;
|
|
use PHPNative\Ui\Widget\Label;
|
|
use PHPNative\Ui\Widget\TextInput;
|
|
use PHPNative\Ui\Window;
|
|
|
|
$storagePath = __DIR__ . '/todo_data.json';
|
|
|
|
$loadTasks = static function (string $path): array {
|
|
if (!is_file($path)) {
|
|
return [];
|
|
}
|
|
|
|
$raw = file_get_contents($path);
|
|
$data = json_decode($raw ?: '[]', true);
|
|
|
|
if (!is_array($data)) {
|
|
return [];
|
|
}
|
|
|
|
// Normalize task structure
|
|
return array_values(array_map(static function ($task) {
|
|
return [
|
|
'id' => $task['id'] ?? uniqid('task_', true),
|
|
'title' => trim((string) ($task['title'] ?? '')),
|
|
'done' => (bool) ($task['done'] ?? false),
|
|
];
|
|
}, $data));
|
|
};
|
|
|
|
$saveTasks = static function (string $path, array $tasks): void {
|
|
file_put_contents(
|
|
$path,
|
|
json_encode($tasks, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE),
|
|
LOCK_EX,
|
|
);
|
|
};
|
|
|
|
$tasks = $loadTasks($storagePath);
|
|
|
|
$app = new Application();
|
|
$window = new Window('Todo Beispiel', 520, 720);
|
|
|
|
$statusLabel = new Label('Bereit.', 'text-sm text-gray-600');
|
|
|
|
$main = new Container('flex flex-col bg-gray-100 gap-4 p-4 h-full w-full');
|
|
$title = new Label('Todo Liste', 'text-2xl font-bold text-black');
|
|
$main->addComponent($title);
|
|
|
|
$input = new TextInput('Neue Aufgabe hinzufügen …', 'flex-1 border border-gray-300 rounded px-3 py-2 bg-white text-black');
|
|
$addButton = new Button('Hinzufügen', 'px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700');
|
|
$inputRow = new Container('flex flex-row gap-3 w-full');
|
|
$inputRow->addComponent($input);
|
|
$inputRow->addComponent($addButton);
|
|
$main->addComponent($inputRow);
|
|
|
|
$listWrapper = new Container('flex-1 w-full overflow-auto bg-white rounded border border-gray-300 p-2');
|
|
$listContainer = new Container('flex flex-col gap-2 w-full');
|
|
$listWrapper->addComponent($listContainer);
|
|
$main->addComponent($listWrapper);
|
|
$main->addComponent($statusLabel);
|
|
|
|
$renderTasks = null;
|
|
$renderTasks = function () use (&$tasks, $listContainer, $statusLabel, $storagePath, $saveTasks, &$renderTasks) {
|
|
$listContainer->clearChildren();
|
|
|
|
if (empty($tasks)) {
|
|
$emptyLabel = new Label('Keine Aufgaben vorhanden. Erstelle die erste oben im Feld.', 'text-sm text-gray-500');
|
|
$listContainer->addComponent($emptyLabel);
|
|
return;
|
|
}
|
|
|
|
foreach ($tasks as $index => $task) {
|
|
$row = new Container('flex flex-row items-center gap-3 w-full border border-gray-200 rounded px-3 py-2 bg-white shadow-sm');
|
|
$taskLabelStyles = $task['done']
|
|
? 'flex-1 text-gray-500 line-through'
|
|
: 'flex-1 text-black';
|
|
$taskLabel = new Label($task['title'], $taskLabelStyles);
|
|
$row->addComponent($taskLabel);
|
|
|
|
$toggleButton = new Button(
|
|
$task['done'] ? 'Reaktivieren' : 'Erledigt',
|
|
$task['done']
|
|
? 'px-3 py-1 text-sm bg-amber-500 text-white rounded hover:bg-amber-600'
|
|
: 'px-3 py-1 text-sm bg-emerald-500 text-white rounded hover:bg-emerald-600',
|
|
);
|
|
|
|
$toggleButton->setOnClick(function () use (&$tasks, $task, $storagePath, $saveTasks, $statusLabel, $renderTasks) {
|
|
foreach ($tasks as &$entry) {
|
|
if ($entry['id'] === $task['id']) {
|
|
$entry['done'] = !$entry['done'];
|
|
break;
|
|
}
|
|
}
|
|
|
|
$saveTasks($storagePath, $tasks);
|
|
$statusLabel->setText(($task['done'] ? 'Aufgabe reaktiviert: ' : 'Aufgabe erledigt: ') . $task['title']);
|
|
$renderTasks();
|
|
});
|
|
|
|
$deleteButton = new Button(
|
|
'Löschen',
|
|
'px-3 py-1 text-sm bg-red-500 text-white rounded hover:bg-red-600',
|
|
);
|
|
|
|
$deleteButton->setOnClick(function () use (&$tasks, $index, $task, $storagePath, $saveTasks, $statusLabel, $renderTasks) {
|
|
array_splice($tasks, $index, 1);
|
|
$saveTasks($storagePath, $tasks);
|
|
$statusLabel->setText('Aufgabe entfernt: ' . $task['title']);
|
|
$renderTasks();
|
|
});
|
|
|
|
$row->addComponent($toggleButton);
|
|
$row->addComponent($deleteButton);
|
|
|
|
$listContainer->addComponent($row);
|
|
}
|
|
};
|
|
|
|
$renderTasks();
|
|
|
|
$addButton->setOnClick(function () use (&$tasks, $input, $saveTasks, $storagePath, $statusLabel, $renderTasks) {
|
|
$title = trim($input->getValue());
|
|
if ($title === '') {
|
|
$statusLabel->setText('Bitte zuerst einen Aufgabentext eingeben.');
|
|
return;
|
|
}
|
|
|
|
$tasks[] = [
|
|
'id' => uniqid('task_', true),
|
|
'title' => $title,
|
|
'done' => false,
|
|
];
|
|
|
|
$saveTasks($storagePath, $tasks);
|
|
$input->setValue('');
|
|
$statusLabel->setText('Aufgabe hinzugefügt: ' . $title);
|
|
$renderTasks();
|
|
});
|
|
|
|
$window->setRoot($main);
|
|
$app->addWindow($window);
|
|
$app->run();
|