game reminders for everybody

This commit is contained in:
Thibault Duplessis 2014-04-20 21:41:39 +02:00
parent 67f07bb9ab
commit 3ed0552b0f
9 changed files with 77 additions and 15 deletions

View file

@ -27,6 +27,7 @@ final class Env(
leaderboard = Env.user.cached.topRatingDay.apply,
progress = Env.user.cached.topProgressDay.apply,
timelineEntries = Env.timeline.getter.userEntries _,
nowPlaying = Env.round.nowPlaying,
dailyPuzzle = Env.puzzle.daily)
lazy val userInfo = mashup.UserInfo(

View file

@ -28,9 +28,10 @@ final class Preload(
leaderboard: Int => Fu[List[User]],
progress: Int => Fu[List[User]],
timelineEntries: String => Fu[List[Entry]],
nowPlaying: (User, Int) => Fu[List[Pov]],
dailyPuzzle: () => Fu[Option[lila.puzzle.DailyPuzzle]]) {
private type RightResponse = (JsObject, List[Entry], List[PostLiteView], List[Created], Option[Game], List[User], List[User], Option[lila.puzzle.DailyPuzzle], Option[Pov])
private type RightResponse = (JsObject, List[Entry], List[PostLiteView], List[Created], Option[Game], List[User], List[User], Option[lila.puzzle.DailyPuzzle], List[Pov])
private type Response = Either[Call, RightResponse]
def apply(
@ -46,7 +47,7 @@ final class Preload(
leaderboard(10) zip
progress(10) zip
dailyPuzzle() zip
(ctx.me ?? GameRepo.lastPlayingByUser) zip
(ctx.me ?? { nowPlaying(_, 3) }) zip
filter map {
case ((((((((((hooks, posts), tours), feat), blocks), entries), leaderboard), progress), puzzle), playing), filter) =>
(Right((Json.obj(

View file

@ -1,4 +1,4 @@
@(preload: String, userTimeline: List[lila.timeline.Entry], forumRecent: List[lila.forum.PostLiteView], tours: List[lila.tournament.Created], featured: Option[Game], leaderboard: List[User], progress: List[User], puzzle: Option[lila.puzzle.DailyPuzzle], playing: Option[Pov])(implicit ctx: Context)
@(preload: String, userTimeline: List[lila.timeline.Entry], forumRecent: List[lila.forum.PostLiteView], tours: List[lila.tournament.Created], featured: Option[Game], leaderboard: List[User], progress: List[User], puzzle: Option[lila.puzzle.DailyPuzzle], playing: List[Pov])(implicit ctx: Context)
@underchat = {
<div id="featured_game" title="@trans.watchLichessTV()">
@ -22,10 +22,14 @@
@goodies = {
@ctx.me.map { u =>
@playing.map { p =>
<a id="now_playing" class="is button" href="@routes.Round.player(p.fullId)">
@playerUsername(p.opponent)<br />@trans.yourTurn()
</a>
@if(playing.nonEmpty) {
<div id="now_playing">
@playing.map { p =>
<a class="is button" href="@routes.Round.player(p.fullId)">
@playerUsername(p.opponent)<br />@trans.yourTurn()
</a>
}
</div>
}
<div id="timeline" data-href="@routes.Lobby.timeline">
@timeline.entries(userTimeline)

@ -1 +1 @@
Subproject commit 441e66ad6e5dda456dd0e12ab2427406b0613210
Subproject commit 49ed2315372c230a938b7120272dd5de65ee5735

View file

@ -70,11 +70,6 @@ trait GameRepo {
$query(Query user userId) sort Query.sortCreated
)
def lastPlayingByUser(user: User): Fu[Option[Pov]] =
(Set("thibault", "veloce") contains user.id) ?? $find(
$query(Query notFinished user.id) sort Query.sortCreated, 1
) map (_.headOption filter (_ turnOf user) flatMap { Pov(_, user) })
def chronologicalFinishedByUser(userId: String): Fu[List[Game]] = $find(
$query(Query.finished ++ Query.rated ++ Query.user(userId)) sort ($sort asc F.createdAt)
)

View file

@ -39,6 +39,7 @@ final class Env(
val ActorName = config getString "actor.name"
val HijackEnabled = config getBoolean "hijack.enabled"
val HijackSalt = config getString "hijack.salt"
val CollectionReminder = config getString "collection.reminder"
}
import settings._
@ -107,6 +108,7 @@ final class Env(
bus = system.lilaBus,
finisher = finisher,
cheatDetector = cheatDetector,
reminder = reminder,
uciMemo = uciMemo)
// public access to AI play, for setup.Processor usage
@ -135,6 +137,9 @@ final class Env(
def version(gameId: String): Fu[Int] =
socketHub ? Ask(gameId, GetVersion) mapTo manifest[Int]
private lazy val reminder = new Reminder(db(CollectionReminder))
def nowPlaying = reminder.nowPlaying
private[round] def animationDelay = AnimationDelay
private[round] def moretimeSeconds = Moretime.toSeconds

View file

@ -15,6 +15,7 @@ private[round] final class Player(
bus: lila.common.Bus,
finisher: Finisher,
cheatDetector: CheatDetector,
reminder: Reminder,
uciMemo: UciMemo) {
def human(play: HumanPlay, round: ActorRef)(pov: Pov): Fu[Events] = play match {
@ -31,6 +32,7 @@ private[round] final class Player(
case (progress, move) =>
(GameRepo save progress) >>-
(pov.game.hasAi ! uciMemo.add(pov.game, move)) >>-
(reminder remind progress.game) >>-
notifyProgress(move, progress, ip) >>
progress.game.finished.fold(
moveFinish(progress.game, color) map { progress.events ::: _ }, {

View file

@ -0,0 +1,51 @@
package lila.round
import lila.db.Types._
import lila.game.{ Game, Pov, GameRepo }
import lila.user.User
import reactivemongo.bson._
private final class Reminder(coll: Coll) {
private case class Remind(_id: String, g: List[String])
private implicit val remindBSONHandler = Macros.handler[Remind]
val nowPlaying: (User, Int) => Fu[List[Pov]] = (user, max) =>
coll.find(BSONDocument("_id" -> user.id)).one[Remind] flatMap {
case None => fuccess(Nil)
case Some(r) =>
val ids = scala.util.Random.shuffle(r.g).take(max).sorted
GameRepo games ids map2 { (g: Game) =>
if (remindable(g) && g.playable && g.turnOf(user)) Some(g)
else {
remove(user.id, g.id)
none
}
} map { _.flatten flatMap { Pov(_, user) } }
}
private[round] def remind(game: Game) {
if (remindable(game)) {
game.players foreach { player =>
player.userId foreach { userId =>
if (game.playable && game.turnOf(player)) add(userId, game.id)
else remove(userId, game.id)
}
}
}
}
private def remindable(game: Game) =
!game.hasAi && game.clock.fold(true)(chess.Speed.isUnlimited)
private def add(userId: String, gameId: String) = coll.update(
BSONDocument("_id" -> userId),
BSONDocument("$addToSet" -> BSONDocument("g" -> gameId)),
upsert = true)
private def remove(userId: String, gameId: String) = coll.update(
BSONDocument("_id" -> userId),
BSONDocument("$pull" -> BSONDocument("g" -> gameId)))
}

View file

@ -1954,13 +1954,16 @@ div.lichess_overboard.joining .mini_board {
font-size: 1.3em;
}
#now_playing {
margin: 2em 0 2em -30px;
margin: 2em 0 1em -30px;
}
#now_playing .button {
display: block;
text-align: center;
position: relative;
padding-left: 45px;
margin-bottom: 1em;
}
#now_playing::before {
#now_playing .button::before {
content: 'U';
font-size: 32px;
position: absolute;