mirror of
https://github.com/YGGverse/Yoda.git
synced 2026-03-31 16:45:27 +00:00
initial commit
This commit is contained in:
parent
ad638650ac
commit
8c2cf42ca7
16 changed files with 541 additions and 0 deletions
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
/vendor/
|
||||||
|
/composer.lock
|
||||||
|
/db.sqlite
|
||||||
|
/config.json
|
||||||
22
composer.json
Normal file
22
composer.json
Normal file
|
|
@ -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"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
145
src/Box/Main.php
Normal file
145
src/Box/Main.php
Normal file
|
|
@ -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
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
30
src/Box/Menu.php
Normal file
30
src/Box/Menu.php
Normal file
|
|
@ -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
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
34
src/Box/Navigation.php
Normal file
34
src/Box/Navigation.php
Normal file
|
|
@ -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
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
20
src/Entry/Address.php
Normal file
20
src/Entry/Address.php
Normal file
|
|
@ -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
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
33
src/Label/Content.php
Normal file
33
src/Label/Content.php
Normal file
|
|
@ -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
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
33
src/Label/Tray.php
Normal file
33
src/Label/Tray.php
Normal file
|
|
@ -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
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
23
src/Menu/Bar/Main.php
Normal file
23
src/Menu/Bar/Main.php
Normal file
|
|
@ -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
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
30
src/Menu/Item/Quit.php
Normal file
30
src/Menu/Item/Quit.php
Normal file
|
|
@ -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();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
29
src/Menu/Item/Yoda.php
Normal file
29
src/Menu/Item/Yoda.php
Normal file
|
|
@ -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
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
11
src/Model/Database.php
Normal file
11
src/Model/Database.php
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Yggverse\Yoda\Model;
|
||||||
|
|
||||||
|
class Database
|
||||||
|
{
|
||||||
|
public function __construct()
|
||||||
|
{}
|
||||||
|
}
|
||||||
54
src/Model/File.php
Normal file
54
src/Model/File.php
Normal file
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
11
src/Model/Memory.php
Normal file
11
src/Model/Memory.php
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Yggverse\Yoda\Model;
|
||||||
|
|
||||||
|
class Memory
|
||||||
|
{
|
||||||
|
public function __construct()
|
||||||
|
{}
|
||||||
|
}
|
||||||
3
src/Theme/Default.css
Normal file
3
src/Theme/Default.css
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
#boxMenu {}
|
||||||
|
#boxNavigation {}
|
||||||
|
#boxMain {}
|
||||||
59
src/Yoda.php
Normal file
59
src/Yoda.php
Normal file
|
|
@ -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…
Add table
Add a link
Reference in a new issue