Yoda/src/Entity/Browser/Container/Page.php
2024-07-26 18:36:12 +03:00

326 lines
No EOL
8.3 KiB
PHP

<?php
declare(strict_types=1);
namespace Yggverse\Yoda\Entity\Browser\Container;
use \Exception;
use \Gtk;
use \GtkBox;
use \GtkOrientation;
use \Yggverse\Yoda\Entity\Browser\Container;
use \Yggverse\Yoda\Model\Connection;
use \Yggverse\Yoda\Model\Filesystem;
class Page
{
// GTK
public GtkBox $gtk;
// Dependencies
public Container $container;
// Requirements
public Page\Title $title;
public Page\Navbar $navbar;
public Page\Progressbar $progressbar;
public Page\Content $content;
public Page\Response $response;
public ?Connection $connection = null;
public function __construct(
Container $container
) {
// Init dependencies
$this->container = $container;
// Init container
$this->gtk = new GtkBox(
GtkOrientation::VERTICAL
);
// Init title
$this->title = new Page\Title(
$this
);
// Init navbar
$this->navbar = new Page\Navbar(
$this
);
$this->gtk->add(
$this->navbar->gtk
);
$this->gtk->set_focus_child(
$this->navbar->update->gtk // replace autofocus priority
);
// Init content
$this->content = new Page\Content(
$this
);
$this->gtk->pack_start(
$this->content->gtk,
true,
true,
0
);
// Init progress bar
$this->progressbar = new Page\Progressbar(
$this
);
$this->gtk->add(
$this->progressbar->gtk
);
// Init response bar
$this->response = new Page\Response(
$this
);
$this->gtk->pack_end(
$this->response->gtk
);
// Render
$this->gtk->show();
}
public function refresh(): void
{
$this->navbar->refresh();
$this->content->refresh();
}
public function init(
?string $request = null,
bool $focus = false
): void
{
if ($request)
{
$this->navbar->request->setValue(
$request
);
}
if ($focus)
{
Gtk::timeout_add(
100,
function()
{
$this->navbar->request->focus();
return false;
}
);
}
}
public function open(
?string $request = null,
bool $history = true
): void
{
$this->navbar->request->setValue(
$request
);
$this->update(
$history
);
}
public function update(
bool $history = true,
int $refresh = 100,
int $timeout = 15
): void
{
// Request entry should not be empty to update
if (empty($this->navbar->request->getValue()))
{
// return;
throw new Exception;
}
// Update title
$this->title->set(
_('Loading...')
);
// Refresh navbar
$this->navbar->refresh();
// Show progressbar
$this->progressbar->infinitive();
// Hide response form
$this->response->hide();
// Drop previous connection
if ($this->connection)
{
// Free memory
$this->connection->close();
}
// Update content using multi-protocol driver
$this->connection = new Connection(
$this->container->browser->database
);
// Async request
$this->connection->request(
$this->navbar->request->getValue(),
$timeout
);
// Calculate expiration time
$expire = time() + $timeout;
// Listen response
Gtk::timeout_add(
$refresh,
function() use ($expire, $history)
{
// Redirect requested
if ($location = $this->connection->getRedirect())
{
// Follow
$this->open(
$location
);
// Hide progressbar
$this->progressbar->hide();
return false; // stop
}
// Response form requested
if ($request = $this->connection->getRequest())
{
// Update title
$this->title->set(
$this->connection->getTitle(),
$this->connection->getSubtitle(),
$this->connection->getTooltip()
);
// Refresh header by new title if current page is active
if ($this === $this->container->tab->get())
{
$this->container->browser->header->setTitle(
$this->title->getValue(),
$this->title->getSubtitle()
);
}
// Show response form
$this->response->show(
$request['placeholder'],
$request['visible']
);
// Hide progressbar
$this->progressbar->hide();
return false; // stop
}
// Stop event loop on request completed
if ($this->connection->isCompleted())
{
// Update title
$this->title->set(
$this->connection->getTitle(),
$this->connection->getSubtitle(),
$this->connection->getTooltip()
);
// Refresh header by new title if current page is active
if ($this === $this->container->tab->get())
{
$this->container->browser->header->setTitle(
$this->title->getValue(),
$this->title->getSubtitle()
);
}
// Update content
$this->content->set(
$this->connection->getMime(),
$this->connection->getData()
);
// Hide progressbar
$this->progressbar->hide();
// Update history
if ($history)
{
// Save request in memory
$this->navbar->history->add(
$this->navbar->request->getValue()
);
// Save request in database (on background)
$pid = pcntl_fork();
if ($pid === 0)
{
$this->container->browser->database->renewHistory(
$this->navbar->request->getValue(),
$this->title->getValue()
);
exit;
}
}
// Stop
return false;
}
// Stop event loop on request expired
if (time() > $expire)
{
// Update title
$this->title->set(
_('Timeout')
);
// Refresh header by new title if current page is active
if ($this === $this->container->tab->get())
{
$this->container->browser->header->setTitle(
$this->title->getValue()
);
}
// Update content
$this->content->set(
Filesystem::MIME_TEXT_PLAIN,
_('Response time reached')
);
// Hide progressbar
$this->progressbar->hide();
// Stop
return false;
}
}
);
}
}