<?phpnamespace App\Form;use App\Chat\TempId;use App\Gui\Awt;use App\Gui\AwtButton;use App\Gui\AwtRadio;use App\Gui\AwtText;use App\Gui\Etched;use App\Gui\TabBar;use App\Net\WsLink;use JumPHP\Gui\Form;use JumPHP\Gui\Label;use JumPHP\Util\Lang;/** * Who you are (nickname, age, sex, city) and the server: what the applet got from the web page (its tempid). The * profile travels to the server as the tempid (TempId). The last values are kept in the options. * * @property TabBar $tabs * @property Etched $card * @property AwtText $nickname * @property AwtText $age * @property AwtRadio $woman * @property AwtRadio $man * @property AwtText $city * @property AwtText $server * @property AwtText $key * @property AwtText $adminKey * @property \JumPHP\Gui\Widget $roleRow * @property \App\Gui\AwtRadio $roleNormal * @property \App\Gui\AwtRadio $roleModo * @property \App\Gui\AwtRadio $roleAdmin * @property Label $status * @property AwtButton $enter */final class LoginForm extends Form{ private float $fontScale = 0; protected function loaded(array $params = []): void { Awt::theme($this); $this->fontScale = 0; // the language of the page (?lang= of the playground or of the site, else the browser's) wins when it changed since // the last visit: someone who reads jumphp.net in English gets the chat in English; a language chosen in the // Options stays as long as the page's does not change $o = $this->engine->options; $page = substr(strtolower((string)\JumPHP\Kernel\Platform::setting('JUMPHP_LANG', '')), 0, 2); if (isset(ChatForm::LANGUAGES[$page]) && $page !== (string)$o->get('lang_page', '')) { $o->set('lang_page', $page); $o->set('lang', $page); } $chosen = (string)$o->get('lang', ''); if (isset(ChatForm::LANGUAGES[$chosen])) { $this->engine->lang->setLang($chosen); } $this->tabs->add('login', 'CaraChat'); $o = $this->engine->options; $this->nickname->text = (string)($params['nickname'] ?? $o->get('nickname', '')); $this->age->text = (string)($params['age'] ?? $o->get('age', '')); $this->city->text = (string)($params['city'] ?? $o->get('city', '')); $woman = (int)($params['sex'] ?? $o->get('sex', 1)) === 0; $this->woman->checked = $woman; $this->man->checked = !$woman; $this->server->text = (string)($params['server'] ?? $o->get('server', self::defaultServer())); $this->key->text = ''; $this->adminKey->text = ''; $this->roleRow->visible = false; $this->probe(trim($this->server->text) ?: self::defaultServer()); $this->status->text = (string)($params['message'] ?? ''); $this->setFocus($this->nickname); // from a partner's site (its connection form, JumPHP embed): its fields, and straight into the chat, as the // applet started from the web page of Caramail $this->site = (string)($params['site'] ?? ''); if (isset($params['sex']) && $params['sex'] !== '') { $sex = (int)$params['sex']; $this->woman->checked = $sex === 0; $this->man->checked = $sex !== 0; } $this->autoEnter = $this->site !== '' && trim((string)($params['nickname'] ?? '')) !== ''; } private string $site = ''; private bool $autoEnter = false; /** The chat server: the one of jumphp.net (a WebSocket on 443), or CARACHAT_SERVER. */ public static function defaultServer(): string { return (string)(getenv('CARACHAT_SERVER') ?: ChatForm::DEFAULT_SERVER); } public function onEnterClick(mixed $sender = null): void { $nickname = trim($this->nickname->text); $server = trim($this->server->text) ?: self::defaultServer(); if ($nickname === '' || preg_match('/[\t:]/', $nickname)) { $this->status->text = Lang::t('A nickname, please'); $this->setFocus($this->nickname); return; } $age = max(0, min(120, (int)$this->age->text)); $sex = $this->woman->checked ? 0 : 1; // the applet's categories: 0 pink (women), 1 blue (men) $city = trim($this->city->text); $o = $this->engine->options; foreach (['nickname' => $nickname, 'age' => $age ?: '', 'sex' => $sex, 'city' => $city, 'server' => $server] as $k => $v) { $o->set($k, $v); } // the administrator's key wins over the moderator's; from the owner's address, the role chosen $key = trim($this->adminKey->text) !== '' ? trim($this->adminKey->text) : trim($this->key->text); $role = !$this->roleRow->visible ? null : ($this->roleAdmin->checked ? 2 : ($this->roleModo->checked ? 1 : 0)); $this->probeLink?->close(); $this->probeLink = null; $this->scenes()->switchTo(ChatForm::class, [ 'server' => $server, 'tempid' => TempId::make($nickname, $age, $sex, $city, $key, TempId::origin($this->site), $role), 'admin' => $role !== null ? $role > 0 : $key !== '', ], false); } private ?WsLink $probeLink = null; private string $probeBuffer = ''; /** * Not of 2002: a short connection to ask the server whether this is the owner's address (700 TAB 1); the form then * offers normal / moderator / administrator. In the browser only (the owner's), never in the tests. */ private function probe(string $server): void { if (!\JumPHP\Kernel\Platform::isWasm() || !WsLink::isUrl($server)) { return; } $link = new WsLink($server); $this->probeLink = $link; $this->probeBuffer = ''; $link->on('data', function (string $bytes) use ($link): void { $this->probeBuffer .= $bytes; while (($end = strpos($this->probeBuffer, "\n")) !== false) { $line = substr($this->probeBuffer, 0, $end); $this->probeBuffer = (string)substr($this->probeBuffer, $end + 1); $f = explode("\t", rtrim($line, "\r")); if ($f[0] === '100') { $link->write("700\t\n"); } elseif ($f[0] === '700') { $this->roleRow->visible = ($f[1] ?? '0') === '1'; $this->invalidate(); $link->close(); $this->probeLink = null; } } }); } protected function tick(float $dt): void { Awt::keepCrisp($this, $this->fontScale); $this->probeLink?->poll(); // a phone: the card at the top of the screen, its fields above the on-screen keyboard (centred, the last ones // would be under it) $justify = $this->breakpoint() === 'xs' ? 'start' : 'center'; if ($this->root !== null && ($this->root->props['justify'] ?? '') !== $justify) { $this->root->props['justify'] = $justify; $this->invalidate(); } if ($this->autoEnter) { $this->autoEnter = false; $this->onEnterClick(); } }}