implement study setClock

pull/3210/head
Thibault Duplessis 2017-07-01 16:44:24 +02:00
parent 1f0e396580
commit cf5efcaccd
8 changed files with 71 additions and 46 deletions

View File

@ -1,6 +1,6 @@
package lila.study
import chess.Color
import chess.{ Color, Centis }
import chess.format.pgn.{ Glyph, Tag }
import chess.variant.Variant
import org.joda.time.DateTime
@ -45,6 +45,9 @@ case class Chapter(
def toggleGlyph(glyph: Glyph, path: Path): Option[Chapter] =
updateRoot(_.toggleGlyphAt(glyph, path))
def setClock(clock: Option[Centis], path: Path): Option[Chapter] =
updateRoot(_.setClockAt(clock, path))
def opening: Option[FullOpening] =
if (!Variant.openingSensibleVariants(setup.variant)) none
else FullOpeningDB searchInFens root.mainline.map(_.fen)

View File

@ -68,6 +68,9 @@ final class ChapterRepo(coll: Coll) {
def setGlyphs(chapter: Chapter, path: Path, glyphs: chess.format.pgn.Glyphs): Funit =
setNodeValue(chapter, path, "g", glyphs.nonEmpty)
def setClock(chapter: Chapter, path: Path, clock: Option[chess.Centis]): Funit =
setNodeValue(chapter, path, "l", clock)
def setChildren(chapter: Chapter, path: Path, children: Node.Children): Funit =
setNodeValue(chapter, path, "n", children.some)

View File

@ -112,19 +112,7 @@ object Node {
}
}
def setShapesAt(shapes: Shapes, path: Path): Option[Children] =
updateAt(path, _ setShapes shapes)
def setCommentAt(comment: Comment, path: Path): Option[Children] =
updateAt(path, _ setComment comment)
def deleteCommentAt(commentId: Comment.Id, path: Path): Option[Children] =
updateAt(path, _ deleteComment commentId)
def toggleGlyphAt(glyph: Glyph, path: Path): Option[Children] =
updateAt(path, _ toggleGlyph glyph)
private def updateAt(path: Path, f: Node => Node): Option[Children] = path.split match {
def updateAt(path: Path, f: Node => Node): Option[Children] = path.split match {
case None => none
case Some((head, Path(Nil))) => updateWith(head, n => Some(f(n)))
case Some((head, tail)) => updateChildren(head, _.updateAt(tail, f))
@ -186,18 +174,26 @@ object Node {
def setShapesAt(shapes: Shapes, path: Path): Option[Root] =
if (path.isEmpty) copy(shapes = shapes).some
else withChildren(_.setShapesAt(shapes, path))
else updateChildrenAt(path, _ setShapes shapes)
def setCommentAt(comment: Comment, path: Path): Option[Root] =
if (path.isEmpty) copy(comments = comments set comment).some
else withChildren(_.setCommentAt(comment, path))
else updateChildrenAt(path, _ setComment comment)
def deleteCommentAt(commentId: Comment.Id, path: Path): Option[Root] =
if (path.isEmpty) copy(comments = comments delete commentId).some
else withChildren(_.deleteCommentAt(commentId, path))
else updateChildrenAt(path, _ deleteComment commentId)
def toggleGlyphAt(glyph: Glyph, path: Path): Option[Root] =
if (path.isEmpty) copy(glyphs = glyphs toggle glyph).some
else withChildren(_.toggleGlyphAt(glyph, path))
else updateChildrenAt(path, _ toggleGlyph glyph)
def setClockAt(clock: Option[Centis], path: Path): Option[Root] =
if (path.isEmpty) copy(clock = clock).some
else updateChildrenAt(path, _ withClock clock)
private def updateChildrenAt(path: Path, f: Node => Node): Option[Root] =
withChildren(_.updateAt(path, f))
def updateMainlineLast(f: Node => Node): Root = children.first.fold(this) { main =>
copy(children = children.update(main updateMainlineLast f))

View File

@ -5,6 +5,7 @@ import play.api.libs.json._
import scala.concurrent.duration._
import chess.format.pgn.Glyphs
import chess.Centis
import lila.hub.TimeBomb
import lila.socket.actorApi.{ Connected => _, _ }
import lila.socket.Socket.Uid
@ -26,7 +27,7 @@ private final class Socket(
import Socket._
import JsonView._
import jsonView.membersWrites
import lila.tree.Node.{ openingWriter, commentWriter, glyphsWriter, shapesWrites }
import lila.tree.Node.{ openingWriter, commentWriter, glyphsWriter, shapesWrites, clockWrites }
private val timeBomb = new TimeBomb(socketTimeout)
@ -145,6 +146,12 @@ private final class Socket(
"w" -> who(uid)
), noMessadata)
case SetClock(pos, clock, uid) => notifyVersion("clock", Json.obj(
"p" -> pos,
"c" -> clock,
"w" -> who(uid)
), noMessadata)
case SetConceal(pos, ply) => notifyVersion("conceal", Json.obj(
"p" -> pos,
"ply" -> ply.map(_.value)
@ -280,6 +287,7 @@ private object Socket {
case class SetComment(position: Position.Ref, comment: Comment, uid: Uid)
case class DeleteComment(position: Position.Ref, commentId: Comment.Id, uid: Uid)
case class SetGlyphs(position: Position.Ref, glyphs: Glyphs, uid: Uid)
case class SetClock(position: Position.Ref, clock: Option[Centis], uid: Uid)
case class ReloadChapters(chapters: List[Chapter.Metadata])
case object ReloadAll
case class ChangeChapter(uid: Uid, position: Position.Ref)

View File

@ -137,16 +137,15 @@ private[study] final class SocketHandler(
}
}
// case ("setClock", o) =>
// import chess.Centis
// import MoveOpts.clockReader
// reading[AtPosition](o) { position =>
// (o \ "d" \ "clock").as[Centis] foreach { clock =>
// member.userId foreach { userId =>
// api.setClock(userId, studyId, position.ref, clock, uid)
// }
// }
// }
case ("setClock", o) =>
import chess.Centis
import MoveOpts.clockReader
reading[AtPosition](o) { position =>
val clock = (o \ "d" \ "clock").asOpt[Centis]
member.userId foreach { userId =>
api.setClock(userId, studyId, position.ref, clock, uid)
}
}
case ("addChapter", o) =>
reading[ChapterMaker.Data](o) { data =>

View File

@ -4,6 +4,7 @@ import akka.actor.{ ActorRef, ActorSelection }
import scala.concurrent.duration._
import chess.format.pgn.Glyph
import chess.Centis
import lila.hub.actorApi.map.Tell
import lila.hub.actorApi.timeline.{ Propagate, StudyCreate, StudyLike }
import lila.hub.Sequencer
@ -290,23 +291,23 @@ final class StudyApi(
}
}
// def setClock(userId: User.ID, studyId: Study.Id, position: Position.Ref, clock: Centis, uid: Uid) = sequenceStudy(studyId) { study =>
// Contribute(userId, study) {
// chapterRepo.byIdAndStudy(position.chapterId, study.id) flatMap {
// _ ?? { chapter =>
// chapter.setClock(clock, position.path) match {
// case Some(newChapter) =>
// studyRepo.updateNow(study)
// chapterRepo.setClock(newChapter, position.path, clock) >>-
// sendTo(study, Socket.SetClock(position, shapes, uid))
// case None =>
// fufail(s"Invalid setShapes $position $shapes") >>-
// reloadUidBecauseOf(study, uid, chapter.id)
// }
// }
// }
// }
// }
def setClock(userId: User.ID, studyId: Study.Id, position: Position.Ref, clock: Option[Centis], uid: Uid) = sequenceStudy(studyId) { study =>
Contribute(userId, study) {
chapterRepo.byIdAndStudy(position.chapterId, study.id) flatMap {
_ ?? { chapter =>
chapter.setClock(clock, position.path) match {
case Some(newChapter) =>
studyRepo.updateNow(study)
chapterRepo.setClock(newChapter, position.path, clock) >>-
sendTo(study, Socket.SetClock(position, clock, uid))
case None =>
fufail(s"Invalid setClock $position $clock") >>-
reloadUidBecauseOf(study, uid, chapter.id)
}
}
}
}
}
def setTag(userId: User.ID, studyId: Study.Id, setTag: actorApi.SetTag, uid: Uid) = sequenceStudy(studyId) { study =>
Contribute(userId, study) {

View File

@ -401,6 +401,14 @@ module.exports = function(data, ctrl, tagTypes, practiceData) {
ctrl.tree.setGlyphsAt(d.g, position.path);
m.redraw();
},
clock: function(d) {
var position = d.p,
who = d.w;
who && members.setActive(who.u);
if (wrongChapter(d)) return;
ctrl.tree.setClockAt(d.c, position.path);
m.redraw();
},
conceal: function(d) {
var position = d.p;
if (wrongChapter(d)) return;

View File

@ -175,6 +175,12 @@ export default function(root: Tree.Node) {
});
}
function setClockAt(clock: number | undefined, path: Tree.Path) {
updateAt(path, function(node) {
node.clock = clock;
});
}
function getParentClock(node: Tree.Node, path: Tree.Path) {
if (!('parentClock' in node)) {
var parent = path && nodeAtPath(treePath.init(path));
@ -211,6 +217,7 @@ export default function(root: Tree.Node) {
setCommentAt: setCommentAt,
deleteCommentAt: deleteCommentAt,
setGlyphsAt: setGlyphsAt,
setClockAt: setClockAt,
pathIsMainline: pathIsMainline,
lastMainlineNode: lastMainlineNode,
pathExists: pathExists,