Browse Source

Fix #130

- Add a little state machine to handle outgoing chat states
- Fix id for composing and paused states in XMPP stanza
- Handle the timeout for the pause on the PHP side only
- Add a little timout on the JS side to don't spam the server at each key pressed
- Cleanup
pull/826/head
Timothée Jaussoin 7 years ago
parent
commit
5bec01debb
  1. 32
      app/widgets/Chat/Chat.php
  2. 22
      app/widgets/Chat/chat.js
  3. 4
      lib/XMPPtoForm.php
  4. 1
      lib/moxl/src/Moxl/Xec/Action/Message/Composing.php
  5. 1
      lib/moxl/src/Moxl/Xec/Action/Message/Paused.php
  6. 4
      lib/moxl/src/Moxl/Xec/Payload/Message.php
  7. 78
      src/Movim/ChatOwnState.php
  8. 2
      src/Movim/ChatStates.php

32
app/widgets/Chat/Chat.php

@ -1,7 +1,5 @@
<?php
use Moxl\Xec\Action\Message\Composing;
use Moxl\Xec\Action\Message\Paused;
use Moxl\Xec\Action\Message\Publish;
use Moxl\Xec\Action\Muc\GetConfig;
@ -19,6 +17,7 @@ use Illuminate\Database\Capsule\Manager as DB;
use Movim\Picture;
use Movim\Session;
use Movim\ChatStates;
use Movim\ChatOwnState;
include_once WIDGETS_PATH.'ContactActions/ContactActions.php';
@ -434,34 +433,7 @@ class Chat extends \Movim\Widget\Base
return;
}
$mc = new Composing;
if ($muc) {
$mc->setMuc();
}
$mc->setTo($to)->request();
}
/**
* @brief Send a "paused" message
*
* @param string $to
* @return void
*/
public function ajaxSendPaused($to, $muc = false)
{
if (!$this->validateJid($to)) {
return;
}
$mp = new Paused;
if ($muc) {
$mp->setMuc();
}
$mp->setTo($to)->request();
(ChatOwnState::getInstance())->composing($to, $muc);
}
/**

22
app/widgets/Chat/chat.js

@ -9,7 +9,7 @@ var Chat = {
edit: false,
// Chat state
state: 0,
composing: false,
since: null,
sended: false,
@ -172,6 +172,7 @@ var Chat = {
focus: function()
{
Chat.sended = false;
Chat.composing = false;
Chat.clearReplace();
Chat.toggleAction();
@ -204,12 +205,12 @@ var Chat = {
return;
}
Chat.state = 0;
Chat.composing = false;
Chat.sendMessage();
return false;
} else if (Chat.state == 0 || Chat.state == 2) {
Chat.state = 1;
} else if (Chat.composing === false) {
Chat.composing = true;
Chat_ajaxSendComposing(this.dataset.jid, Boolean(this.dataset.muc));
Chat.since = new Date().getTime();
}
@ -217,17 +218,14 @@ var Chat = {
textarea.onkeyup = function(event) {
localStorage.setItem(this.dataset.jid + '_message', this.value);
// A little timeout to not spam the server with composing states
setTimeout(function()
{
var textarea = document.querySelector('#chat_textarea');
if (textarea
&& Chat.state == 1
&& Chat.since + 5000 < new Date().getTime()) {
Chat.state = 2;
Chat_ajaxSendPaused(textarea.dataset.jid, Boolean(textarea.dataset.muc));
if (Chat.since + 3000 < new Date().getTime()) {
Chat.composing = false;
}
},5000);
}, 3000);
Chat.toggleAction();
};

4
lib/XMPPtoForm.php

@ -35,11 +35,7 @@ class XMPPtoForm
public function create()
{
//$this->xmpp = str_replace('xmlns=', 'ns=', $this->xmpp);
//$x = new SimpleXMLElement($this->xmpp);
foreach ($this->xmpp->children() as $element) {
\Utils::debug($element->getName());
switch ($element->getName()) {
case 'title':
$this->outTitle($element);

1
lib/moxl/src/Moxl/Xec/Action/Message/Composing.php

@ -13,6 +13,7 @@ class Composing extends Action
public function request()
{
$this->store();
if ($this->_muc) {
Muc::composing($this->_to);
} else {

1
lib/moxl/src/Moxl/Xec/Action/Message/Paused.php

@ -13,6 +13,7 @@ class Paused extends Action
public function request()
{
$this->store();
if ($this->_muc) {
Muc::paused($this->_to);
} else {

4
lib/moxl/src/Moxl/Xec/Payload/Message.php

@ -18,6 +18,10 @@ class Message extends Payload
return;
}
if ($stanza->attributes()->type == 'error') {
return;
}
if ($stanza->composing) {
(ChatStates::getInstance())->composing($from, $to);
}

78
src/Movim/ChatOwnState.php

@ -0,0 +1,78 @@
<?php
namespace Movim;
use Movim\Widget\Wrapper;
use React\EventLoop\Timer\Timer;
use Moxl\Xec\Action\Message\Composing;
use Moxl\Xec\Action\Message\Paused;
/**
* This class handle all the outgoing chatstates
*/
class ChatOwnState
{
protected static $instance;
private $_to = null;
private $_muc = false;
private $_timer;
private $_timeout = 5;
public static function getInstance()
{
if (!isset(self::$instance)) {
self::$instance = new self();
}
return self::$instance;
}
public function composing(string $to, bool $muc = false)
{
global $loop;
if ($this->_to !== $to) {
$mc = new Composing;
if ($muc) {
$mc->setMuc();
}
$mc->setTo($to)->request();
if ($this->_to !== null) {
$this->paused($this->_to, $this->_muc);
}
$this->_to = $to;
$this->_muc = $muc;
}
if ($this->_timer) {
$loop->cancelTimer($this->_timer);
}
$this->_timer = $loop->addTimer($this->_timeout, function () use ($to, $muc) {
$this->paused($to, $muc);
});
}
private function paused(string $to, bool $muc = false)
{
global $loop;
$mp = new Paused;
$this->_to = null;
$this->_muc = false;
$loop->cancelTimer($this->_timer);
if ($muc) {
$mp->setMuc();
}
$mp->setTo($to)->request();
}
}

2
src/Movim/ChatStates.php

@ -30,10 +30,8 @@ class ChatStates
if (array_key_exists($jid, $this->_composing)) {
if ($resource !== null) {
\Utils::debug($resource);
if (array_key_exists($resource, $this->_composing[$jid])
&& $this->_composing[$jid][$resource] instanceof Timer) {
\Utils::debug('clear '.$resource);
$loop->cancelTimer($this->_composing[$jid][$resource]);
unset($this->_composing[$jid][$resource]);

Loading…
Cancel
Save