show realtime user game in powertip

pull/83/head
Thibault Duplessis 2013-12-24 14:58:54 +01:00
parent a6235e8a39
commit 7f6314e3ac
7 changed files with 131 additions and 121 deletions

View File

@ -5,6 +5,7 @@ import play.api.mvc._, Results._
import lila.app._
import lila.common.LilaCookie
import lila.db.api.$find
import lila.game.GameRepo
import lila.security.Permission
import lila.user.tube.userTube
import lila.user.{ Context, User UserModel, UserRepo }
@ -21,7 +22,9 @@ object User extends LilaController {
}
def showMini(username: String) = Open { implicit ctx
mini(username)
OptionFuOk(UserRepo named username) { user
GameRepo nowPlaying user.id map { html.user.mini(user, _) }
}
}
def showFilter(username: String, filterName: String, page: Int) = Open { implicit ctx
@ -53,12 +56,6 @@ object User extends LilaController {
})
} yield html.user.show(u, info, pag, filters)
private def mini(username: String)(implicit ctx: Context) =
OptionOk(UserRepo named username) { user
Thread sleep 200
html.user.mini(user)
}
def list(page: Int) = Open { implicit ctx
Reasonable(page) {
val nb = 10

View File

@ -1,25 +1,27 @@
@(userId: String, signup: Boolean = false)(implicit ctx: Context)
@(userId: String, signup: Boolean = false, playing: Boolean = false)(implicit ctx: Context)
@ctx.userId.map { myId =>
@if(myId != userId) {
@if(!blocks(userId, myId)) {
@if(!playing) {
<a title="@trans.challengeToPlay()" href="@routes.Lobby.home()?username=@userIdToUsername(userId)#friend" class="icon button" href="#">
<span class="s16 challenge"></span>
</a>
}
<a title="@trans.composeMessage()" href="@routes.Message.form()?username=@userId" class="icon button" href="#">
<span class="s16 message"></span>
</a>
}
@relationWith(userId) match {
case None => {
<a
class="icon button relation"
href="@routes.Relation.block(userId)"
<a
class="icon button relation"
href="@routes.Relation.block(userId)"
title="@trans.block()">
<span class="s16 tdown"></span>
</a>
<a
class="icon button relation"
<a
class="icon button relation"
href="@routes.Relation.follow(userId)"
title="@trans.follow()">
<span class="s16 tup"></span>

View File

@ -1,23 +1,26 @@
@(u: User)(implicit ctx: Context)
@(u: User, playing: Option[Game])(implicit ctx: Context)
<div class="title">
<span class="user_link @isOnline(u.id).fold("online", "offline")">
<strong title="Glicko rating">@u.rating</strong>
<small title="Glicko rating deviation">±@u.perfs.global.glicko.intDeviation</small>
<small title="Glicko rating deviation">±@u.perfs.global.glicko.intDeviation</small>
@showProgress(u.progress)
@u.count.game.localize @trans.games()
</span>
<p class="localization">
@u.profileOrDefault.countryInfo.map {
case (code, name) => {
<span class="country"><img src="@staticUrl(s"images/flag/shiny/16/$code.png")" /> @name</span>
}
}
@u.lang.flatMap(langName).map { name =>
<span class="lang s16">@name</span>
}
@u.profileOrDefault.countryInfo.map {
case (code, name) => {
<span class="country"><img src="@staticUrl(s"images/flag/shiny/16/$code.png")" /> @name</span>
}
}
@u.lang.flatMap(langName).map { name =>
<span class="lang s16">@name</span>
}
</p>
@if(followsMe(u.id)) {
@trans.followsYou()
}
@playing.map { g =>
@gameFen(g, g.player(u).getOrElse(g.firstPlayer).color)
}
</div>
<div class="content relation_actions">@relation.actions(u.id)</div>
<div class="content relation_actions">@relation.actions(u.id, playing = playing.isDefined)</div>

View File

@ -164,6 +164,11 @@ trait GameRepo {
$count(Json.obj(BSONFields.createdAt -> ($gte($date(from)) ++ $lt($date(to)))))
}).sequenceFu
def nowPlaying(userId: String): Fu[Option[Game]] =
$find.one(Query.status(Status.Started) ++ Query.user(userId) ++ Json.obj(
BSONFields.createdAt -> $gt($date(DateTime.now - 30.minutes))
))
def bestOpponents(userId: String, limit: Int): Fu[List[(String, Int)]] = {
import reactivemongo.bson._
import reactivemongo.core.commands._

View File

@ -5,7 +5,6 @@ import scala.concurrent.duration._
import akka.actor._
import akka.pattern.{ ask, pipe }
import chess.Color
import makeTimeout.short
import play.api.libs.json.{ JsObject, Json }
import actorApi._, round._
@ -16,6 +15,7 @@ import lila.security.Flood
import lila.socket.actorApi.{ Connected _, _ }
import lila.socket.Handler
import lila.user.{ User, Context }
import makeTimeout.short
private[round] final class SocketHandler(
roundMap: ActorRef,
@ -78,6 +78,9 @@ private[round] final class SocketHandler(
case ("challenge", o) ((o str "d") |@| member.userId).tupled foreach {
case (to, from) hub.actor.challenger ! lila.hub.actorApi.setup.RemindChallenge(gameId, from, to)
}
case ("liveGames", o) o str "d" foreach { ids
socket ! LiveGames(uid, ids.split(' ').toList)
}
}
}
}

View File

@ -13,8 +13,8 @@ final class SocketHub extends Actor {
private val sockets = collection.mutable.Set[ActorRef]()
context.system.lilaBus.subscribe(self,
'moveEvent, 'users, 'deploy, 'nbMembers, 'socket,
context.system.lilaBus.subscribe(self,
'moveEvent, 'users, 'deploy, 'nbMembers, 'socket,
// FIXME this event only concern the current TV room
'changeFeaturedGame)

View File

@ -42,7 +42,13 @@ var storage = {
//////////////////
var strongSocketDefaults = {
events: {},
events: {
fen: function(e) {
$('a.live_' + e.id).each(function() {
parseFen($(this).data("fen", e.fen).data("lastmove", e.lm));
});
}
},
params: {
sri: lichess_sri
},
@ -498,6 +504,7 @@ var storage = {
url: $(this).attr('href') + '/mini',
success: function(html) {
$('#powerTip').html(html);
$('body').trigger('lichess.content_loaded');
}
});
}
@ -1739,93 +1746,93 @@ var storage = {
// gamelist.js //
/////////////////
$(function() {
function parseFen($elem) {
if (!$elem || !$elem.jquery) {
$elem = $('.parse_fen');
}
$elem.each(function() {
var $this = $(this);
var color = $this.data('color') || "white";
var withKeys = $this.hasClass('with_keys');
var letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'];
var fen = $this.data('fen').split(' ')[0].replace(/\//g, '');
var lm = $this.data('lastmove');
var lastMove = lm ? [lm[0] + lm[1], lm[2] + lm[3]] : [];
var x, y, html = '',
scolor, pcolor, pclass, c, d, increment;
var pclasses = {
'p': 'pawn',
'r': 'rook',
'n': 'knight',
'b': 'bishop',
'q': 'queen',
'k': 'king'
};
var pregex = /(p|r|n|b|q|k)/;
if ('white' == color) {
x = 8;
y = 1;
increment = function() {
y++;
if (y > 8) {
y = 1;
x--;
}
};
} else {
x = 1;
y = 8;
increment = function() {
y--;
if (y < 1) {
y = 8;
x++;
}
};
}
function openSquare(x, y) {
var key = 'white' == color ? letters[y - 1] + x : letters[8 - y] + (9 - x);
var scolor = (x + y) % 2 ? 'white' : 'black';
if ($.inArray(key, lastMove) != -1) scolor += " moved";
var html = '<div class="lmcs ' + scolor + '" style="top:' + (28 * (8 - x)) + 'px;left:' + (28 * (y - 1)) + 'px;"';
if (withKeys) {
html += ' data-key="' + key + '"';
}
return html + '>';
}
function closeSquare() {
return '</div>';
}
for (var fenIndex in fen) {
c = fen[fenIndex];
html += openSquare(x, y);
if (!isNaN(c)) { // it is numeric
html += closeSquare();
increment();
for (d = 1; d < c; d++) {
html += openSquare(x, y) + closeSquare();
increment();
}
} else {
pcolor = pregex.test(c) ? 'black' : 'white';
pclass = pclasses[c.toLowerCase()];
html += '<div class="lcmp ' + pclass + ' ' + pcolor + '"></div>';
html += closeSquare();
increment();
}
}
$this.html(html).removeClass('parse_fen');
// attempt to free memory
html = pclasses = increment = pregex = fen = $this = 0;
});
function parseFen($elem) {
if (!$elem || !$elem.jquery) {
$elem = $('.parse_fen');
}
$elem.each(function() {
var $this = $(this);
var color = $this.data('color') || "white";
var withKeys = $this.hasClass('with_keys');
var letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'];
var fen = $this.data('fen').split(' ')[0].replace(/\//g, '');
var lm = $this.data('lastmove');
var lastMove = lm ? [lm[0] + lm[1], lm[2] + lm[3]] : [];
var x, y, html = '',
scolor, pcolor, pclass, c, d, increment;
var pclasses = {
'p': 'pawn',
'r': 'rook',
'n': 'knight',
'b': 'bishop',
'q': 'queen',
'k': 'king'
};
var pregex = /(p|r|n|b|q|k)/;
if ('white' == color) {
x = 8;
y = 1;
increment = function() {
y++;
if (y > 8) {
y = 1;
x--;
}
};
} else {
x = 1;
y = 8;
increment = function() {
y--;
if (y < 1) {
y = 8;
x++;
}
};
}
function openSquare(x, y) {
var key = 'white' == color ? letters[y - 1] + x : letters[8 - y] + (9 - x);
var scolor = (x + y) % 2 ? 'white' : 'black';
if ($.inArray(key, lastMove) != -1) scolor += " moved";
var html = '<div class="lmcs ' + scolor + '" style="top:' + (28 * (8 - x)) + 'px;left:' + (28 * (y - 1)) + 'px;"';
if (withKeys) {
html += ' data-key="' + key + '"';
}
return html + '>';
}
function closeSquare() {
return '</div>';
}
for (var fenIndex in fen) {
c = fen[fenIndex];
html += openSquare(x, y);
if (!isNaN(c)) { // it is numeric
html += closeSquare();
increment();
for (d = 1; d < c; d++) {
html += openSquare(x, y) + closeSquare();
increment();
}
} else {
pcolor = pregex.test(c) ? 'black' : 'white';
pclass = pclasses[c.toLowerCase()];
html += '<div class="lcmp ' + pclass + ' ' + pcolor + '"></div>';
html += closeSquare();
increment();
}
}
$this.html(html).removeClass('parse_fen');
// attempt to free memory
html = pclasses = increment = pregex = fen = $this = 0;
});
}
$(function() {
parseFen();
$('body').on('lichess.content_loaded', parseFen);
@ -1847,13 +1854,6 @@ var storage = {
registerLiveGames();
});
lichess.socketDefaults.events.fen = function(e) {
$('a.live_' + e.id).each(function() {
var $this = $(this);
parseFen($this.data("fen", e.fen).data("lastmove", e.lm));
});
};
$('div.checkmateCaptcha').each(function() {
var $captcha = $(this);
var color = $captcha.find('.mini_board').data('color');