mirror of https://github.com/YGGverse/Yoda.git
yggverse
8 months ago
16 changed files with 541 additions and 0 deletions
@ -0,0 +1,4 @@ |
|||||||
|
/vendor/ |
||||||
|
/composer.lock |
||||||
|
/db.sqlite |
||||||
|
/config.json |
@ -0,0 +1,22 @@ |
|||||||
|
{ |
||||||
|
"name": "yggverse/yoda", |
||||||
|
"description": "PHP-GTK Client for Gemini Protocol", |
||||||
|
"keywords": [ "php-gtk", "gtk", "gtk3", "gemini", "gemini-protocol", "client", "browser", "altweb" ], |
||||||
|
"homepage": "https://github.com/YGGverse/Yoda", |
||||||
|
"type": "project", |
||||||
|
"require": { |
||||||
|
"yggverse/gemini": "^0.7.0", |
||||||
|
"yggverse/net": "^1.7" |
||||||
|
}, |
||||||
|
"license": "MIT", |
||||||
|
"autoload": { |
||||||
|
"psr-4": { |
||||||
|
"Yggverse\\Yoda\\": "src/" |
||||||
|
} |
||||||
|
}, |
||||||
|
"authors": [ |
||||||
|
{ |
||||||
|
"name": "YGGverse" |
||||||
|
} |
||||||
|
] |
||||||
|
} |
@ -0,0 +1,145 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
declare(strict_types=1); |
||||||
|
|
||||||
|
namespace Yggverse\Yoda\Box; |
||||||
|
|
||||||
|
class Main |
||||||
|
{ |
||||||
|
public \GtkBox $box; |
||||||
|
|
||||||
|
public \Yggverse\Yoda\Box\Menu $menu; |
||||||
|
public \Yggverse\Yoda\Box\Navigation $navigation; |
||||||
|
public \Yggverse\Yoda\Label\Content $content; |
||||||
|
public \Yggverse\Yoda\Label\Tray $tray; |
||||||
|
|
||||||
|
public function __construct( |
||||||
|
string $name = 'boxMain' |
||||||
|
) { |
||||||
|
$this->box = new \GtkBox( |
||||||
|
\GtkOrientation::VERTICAL |
||||||
|
); |
||||||
|
|
||||||
|
$this->box->set_name( |
||||||
|
$name |
||||||
|
); |
||||||
|
|
||||||
|
// Init dependencies |
||||||
|
$this->menu = new \Yggverse\Yoda\Box\Menu(); |
||||||
|
|
||||||
|
$this->box->pack_start( |
||||||
|
$this->menu->box, |
||||||
|
false, |
||||||
|
true, |
||||||
|
0 |
||||||
|
); |
||||||
|
|
||||||
|
$this->navigation = new \Yggverse\Yoda\Box\Navigation(); |
||||||
|
|
||||||
|
$this->box->pack_start( |
||||||
|
$this->navigation->box, |
||||||
|
false, |
||||||
|
true, |
||||||
|
0 |
||||||
|
); |
||||||
|
|
||||||
|
$this->content = new \Yggverse\Yoda\Label\Content(); |
||||||
|
|
||||||
|
$scroll = new \GtkScrolledWindow(); |
||||||
|
|
||||||
|
$scroll->add( |
||||||
|
$this->content->label |
||||||
|
); |
||||||
|
|
||||||
|
$this->box->pack_start( |
||||||
|
$scroll, |
||||||
|
true, |
||||||
|
true, |
||||||
|
10 |
||||||
|
); |
||||||
|
|
||||||
|
$this->tray = new \Yggverse\Yoda\Label\Tray(); |
||||||
|
|
||||||
|
$this->box->pack_start( |
||||||
|
$this->tray->label, |
||||||
|
false, |
||||||
|
true, |
||||||
|
0 |
||||||
|
); |
||||||
|
|
||||||
|
$this->navigation->address->entry->connect( |
||||||
|
'activate', |
||||||
|
function ($entry) |
||||||
|
{ |
||||||
|
global $config; |
||||||
|
|
||||||
|
$host = null; |
||||||
|
|
||||||
|
if ($config->resolver->enabled) |
||||||
|
{ |
||||||
|
$resolve = new \Yggverse\Net\Resolve( |
||||||
|
$config->resolver->request->record, |
||||||
|
$config->resolver->request->host, |
||||||
|
$config->resolver->request->timeout, |
||||||
|
$config->resolver->result->shuffle |
||||||
|
); |
||||||
|
|
||||||
|
$address = new \Yggverse\Net\Address( |
||||||
|
$entry->get_text() |
||||||
|
); |
||||||
|
|
||||||
|
$resolved = $resolve->address( |
||||||
|
$address |
||||||
|
); |
||||||
|
|
||||||
|
if ($resolved) |
||||||
|
{ |
||||||
|
$host = $resolved->getHost(); // @TODO memory cache |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
$request = new \Yggverse\Gemini\Client\Request( |
||||||
|
$entry->get_text(), |
||||||
|
$host |
||||||
|
); |
||||||
|
|
||||||
|
$this->tray->label->set_text( |
||||||
|
sprintf( |
||||||
|
'Open %s...', |
||||||
|
$entry->get_text() |
||||||
|
) |
||||||
|
); |
||||||
|
|
||||||
|
$start = microtime(true); |
||||||
|
|
||||||
|
$raw = $request->getResponse(); |
||||||
|
|
||||||
|
$end = microtime(true); |
||||||
|
|
||||||
|
$response = new \Yggverse\Gemini\Client\Response( |
||||||
|
$raw |
||||||
|
); |
||||||
|
|
||||||
|
$this->content->label->set_markup( |
||||||
|
$response->getBody() |
||||||
|
); |
||||||
|
|
||||||
|
$this->tray->label->set_text( |
||||||
|
sprintf( |
||||||
|
'%s | %s | %d bytes | %s seconds', |
||||||
|
date('c'), |
||||||
|
$response->getMeta() ? $response->getMeta() : $response->getCode(), |
||||||
|
number_format( |
||||||
|
mb_strlen( |
||||||
|
$raw |
||||||
|
) |
||||||
|
), |
||||||
|
round( |
||||||
|
$end - $start, 2 |
||||||
|
) |
||||||
|
) |
||||||
|
); |
||||||
|
} |
||||||
|
); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,30 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
declare(strict_types=1); |
||||||
|
|
||||||
|
namespace Yggverse\Yoda\Box; |
||||||
|
|
||||||
|
class Menu |
||||||
|
{ |
||||||
|
public \GtkBox $box; |
||||||
|
|
||||||
|
public \Yggverse\Yoda\Menu\Bar\Main $main; |
||||||
|
|
||||||
|
public function __construct( |
||||||
|
string $name = 'boxMenu' |
||||||
|
) { |
||||||
|
$this->box = new \GtkBox( |
||||||
|
\GtkOrientation::VERTICAL |
||||||
|
); |
||||||
|
|
||||||
|
$this->box->set_name( |
||||||
|
$name |
||||||
|
); |
||||||
|
|
||||||
|
$this->main = new \Yggverse\Yoda\Menu\Bar\Main(); |
||||||
|
|
||||||
|
$this->box->add( |
||||||
|
$this->main->bar |
||||||
|
); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,34 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
declare(strict_types=1); |
||||||
|
|
||||||
|
namespace Yggverse\Yoda\Box; |
||||||
|
|
||||||
|
class Navigation |
||||||
|
{ |
||||||
|
public \GtkBox $box; |
||||||
|
|
||||||
|
public \Yggverse\Yoda\Entry\Address $address; |
||||||
|
|
||||||
|
public function __construct( |
||||||
|
string $name = 'boxNavigation' |
||||||
|
) { |
||||||
|
global $config; |
||||||
|
|
||||||
|
$this->box = new \GtkBox( |
||||||
|
\GtkOrientation::VERTICAL |
||||||
|
); |
||||||
|
|
||||||
|
$this->box->set_name( |
||||||
|
$name |
||||||
|
); |
||||||
|
|
||||||
|
$this->address = new \Yggverse\Yoda\Entry\Address( |
||||||
|
$config->homepage |
||||||
|
); |
||||||
|
|
||||||
|
$this->box->add( |
||||||
|
$this->address->entry |
||||||
|
); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,20 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
declare(strict_types=1); |
||||||
|
|
||||||
|
namespace Yggverse\Yoda\Entry; |
||||||
|
|
||||||
|
class Address |
||||||
|
{ |
||||||
|
public \GtkEntry $entry; |
||||||
|
|
||||||
|
public function __construct( |
||||||
|
?string $value = null |
||||||
|
) { |
||||||
|
$this->entry = new \GtkEntry(); |
||||||
|
|
||||||
|
$this->entry->set_text( |
||||||
|
$value |
||||||
|
); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,33 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
declare(strict_types=1); |
||||||
|
|
||||||
|
namespace Yggverse\Yoda\Label; |
||||||
|
|
||||||
|
class Content |
||||||
|
{ |
||||||
|
public \GtkLabel $label; |
||||||
|
|
||||||
|
public function __construct(string $value = '') |
||||||
|
{ |
||||||
|
$this->label = new \GtkLabel( |
||||||
|
$value |
||||||
|
); |
||||||
|
|
||||||
|
$this->label->set_use_markup( |
||||||
|
true |
||||||
|
); |
||||||
|
|
||||||
|
$this->label->set_selectable( |
||||||
|
true |
||||||
|
); |
||||||
|
|
||||||
|
$this->label->set_xalign( |
||||||
|
0 |
||||||
|
); |
||||||
|
|
||||||
|
$this->label->set_yalign( |
||||||
|
0 |
||||||
|
); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,33 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
declare(strict_types=1); |
||||||
|
|
||||||
|
namespace Yggverse\Yoda\Label; |
||||||
|
|
||||||
|
class Tray |
||||||
|
{ |
||||||
|
public \GtkLabel $label; |
||||||
|
|
||||||
|
public function __construct(string $value = '') |
||||||
|
{ |
||||||
|
$this->label = new \GtkLabel( |
||||||
|
$value |
||||||
|
); |
||||||
|
|
||||||
|
$this->label->set_use_markup( |
||||||
|
true |
||||||
|
); |
||||||
|
|
||||||
|
$this->label->set_selectable( |
||||||
|
false |
||||||
|
); |
||||||
|
|
||||||
|
$this->label->set_xalign( |
||||||
|
0 |
||||||
|
); |
||||||
|
|
||||||
|
$this->label->set_yalign( |
||||||
|
0 |
||||||
|
); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,23 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
declare(strict_types=1); |
||||||
|
|
||||||
|
namespace Yggverse\Yoda\Menu\Bar; |
||||||
|
|
||||||
|
class Main |
||||||
|
{ |
||||||
|
public \GtkMenuBar $bar; |
||||||
|
|
||||||
|
public \Yggverse\Yoda\Menu\Item\Yoda $yoda; |
||||||
|
|
||||||
|
public function __construct() |
||||||
|
{ |
||||||
|
$this->bar = new \GtkMenuBar(); |
||||||
|
|
||||||
|
$this->yoda = new \Yggverse\Yoda\Menu\Item\Yoda(); |
||||||
|
|
||||||
|
$this->bar->append( |
||||||
|
$this->yoda->item |
||||||
|
); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,30 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
declare(strict_types=1); |
||||||
|
|
||||||
|
namespace Yggverse\Yoda\Menu\Item; |
||||||
|
|
||||||
|
class Quit |
||||||
|
{ |
||||||
|
public \GtkMenuItem $item; |
||||||
|
|
||||||
|
public function __construct(string $label = 'Quit') |
||||||
|
{ |
||||||
|
$this->item = \GtkMenuItem::new_with_label( |
||||||
|
$label |
||||||
|
); |
||||||
|
|
||||||
|
$this->activate(); |
||||||
|
} |
||||||
|
|
||||||
|
public function activate(): void |
||||||
|
{ |
||||||
|
$this->item->connect( |
||||||
|
'activate', |
||||||
|
function () |
||||||
|
{ |
||||||
|
\Gtk::main_quit(); |
||||||
|
} |
||||||
|
); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,29 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
declare(strict_types=1); |
||||||
|
|
||||||
|
namespace Yggverse\Yoda\Menu\Item; |
||||||
|
|
||||||
|
class Yoda |
||||||
|
{ |
||||||
|
public \GtkMenuItem $item; |
||||||
|
|
||||||
|
public function __construct(string $label = 'Yoda') |
||||||
|
{ |
||||||
|
$this->item = \GtkMenuItem::new_with_label( |
||||||
|
$label |
||||||
|
); |
||||||
|
|
||||||
|
$children = new \GtkMenu(); |
||||||
|
|
||||||
|
$quit = new \Yggverse\Yoda\Menu\Item\Quit(); |
||||||
|
|
||||||
|
$children->append( |
||||||
|
$quit->item |
||||||
|
); |
||||||
|
|
||||||
|
$this->item->set_submenu( |
||||||
|
$children |
||||||
|
); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,11 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
declare(strict_types=1); |
||||||
|
|
||||||
|
namespace Yggverse\Yoda\Model; |
||||||
|
|
||||||
|
class Database |
||||||
|
{ |
||||||
|
public function __construct() |
||||||
|
{} |
||||||
|
} |
@ -0,0 +1,54 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
declare(strict_types=1); |
||||||
|
|
||||||
|
namespace Yggverse\Yoda\Model; |
||||||
|
|
||||||
|
class File |
||||||
|
{ |
||||||
|
public static function getConfig(): object |
||||||
|
{ |
||||||
|
$filename = __DIR__ . |
||||||
|
DIRECTORY_SEPARATOR . '..' . |
||||||
|
DIRECTORY_SEPARATOR . '..' . |
||||||
|
DIRECTORY_SEPARATOR . 'config.json'; |
||||||
|
|
||||||
|
if (file_exists($filename) && is_readable($filename)) |
||||||
|
{ |
||||||
|
$result = json_decode( |
||||||
|
file_get_contents( |
||||||
|
$filename |
||||||
|
) |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
if (empty($result)) |
||||||
|
{ |
||||||
|
throw new \Exception(); // @TODO |
||||||
|
} |
||||||
|
|
||||||
|
return $result; |
||||||
|
} |
||||||
|
|
||||||
|
public static function getTheme(string $name): string |
||||||
|
{ |
||||||
|
$filename = __DIR__ . |
||||||
|
DIRECTORY_SEPARATOR . '..' . |
||||||
|
DIRECTORY_SEPARATOR . 'Theme' . |
||||||
|
DIRECTORY_SEPARATOR . $name . '.css'; |
||||||
|
|
||||||
|
if (file_exists($filename) && is_readable($filename)) |
||||||
|
{ |
||||||
|
$result = file_get_contents( |
||||||
|
$filename |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
if (empty($result)) |
||||||
|
{ |
||||||
|
throw new \Exception(); // @TODO |
||||||
|
} |
||||||
|
|
||||||
|
return $result; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,11 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
declare(strict_types=1); |
||||||
|
|
||||||
|
namespace Yggverse\Yoda\Model; |
||||||
|
|
||||||
|
class Memory |
||||||
|
{ |
||||||
|
public function __construct() |
||||||
|
{} |
||||||
|
} |
@ -0,0 +1,59 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
// Load dependencies |
||||||
|
require_once __DIR__ . |
||||||
|
DIRECTORY_SEPARATOR . '..'. |
||||||
|
DIRECTORY_SEPARATOR . 'vendor' . |
||||||
|
DIRECTORY_SEPARATOR . 'autoload.php'; |
||||||
|
|
||||||
|
// Init config |
||||||
|
$config = \Yggverse\Yoda\Model\File::getConfig(); |
||||||
|
|
||||||
|
// Init GTK |
||||||
|
\Gtk::init(); |
||||||
|
|
||||||
|
// Init theme |
||||||
|
$css = new \GtkCssProvider(); |
||||||
|
|
||||||
|
$css->load_from_data( |
||||||
|
\Yggverse\Yoda\Model\File::getTheme( |
||||||
|
$config->theme |
||||||
|
) |
||||||
|
); |
||||||
|
|
||||||
|
$style = new \GtkStyleContext(); |
||||||
|
|
||||||
|
$style->add_provider_for_screen( |
||||||
|
$css, |
||||||
|
600 |
||||||
|
); |
||||||
|
|
||||||
|
// Init app window |
||||||
|
$window = new \GtkWindow(); |
||||||
|
|
||||||
|
$window->set_size_request( |
||||||
|
600, |
||||||
|
480 |
||||||
|
); |
||||||
|
|
||||||
|
$window->set_title( |
||||||
|
'Yoda' |
||||||
|
); |
||||||
|
|
||||||
|
$window->connect( |
||||||
|
'destroy', |
||||||
|
function() |
||||||
|
{ |
||||||
|
\Gtk::main_quit(); |
||||||
|
} |
||||||
|
); |
||||||
|
|
||||||
|
$main = new \Yggverse\Yoda\Box\Main(); |
||||||
|
|
||||||
|
$window->add( |
||||||
|
$main->box |
||||||
|
); |
||||||
|
|
||||||
|
$window->show_all(); |
||||||
|
|
||||||
|
\Gtk::main(); |
Loading…
Reference in new issue