relay live clock WIP
parent
81a4ab54d2
commit
e9fc1de4dc
|
@ -49,8 +49,7 @@ object Relay {
|
|||
|
||||
def set(v: Boolean) = copy(
|
||||
until = v option DateTime.now.plusHours(3),
|
||||
nextAt = DateTime.now.plusSeconds(1).some,
|
||||
log = SyncLog(Vector.empty)
|
||||
nextAt = DateTime.now.plusSeconds(1).some
|
||||
)
|
||||
|
||||
override def toString = upstream.toString
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package lila.relay
|
||||
|
||||
import org.joda.time.DateTime
|
||||
|
||||
import chess.format.pgn.Tag
|
||||
import lila.common.{ LilaException, Chronometer }
|
||||
import lila.socket.Socket.Uid
|
||||
|
@ -68,7 +70,8 @@ private final class RelaySync(
|
|||
position = position,
|
||||
rawNode = n,
|
||||
uid = socketUid,
|
||||
opts = moveOpts.copy(clock = n.clock)
|
||||
opts = moveOpts.copy(clock = n.clock),
|
||||
relayMoveAt = DateTime.now.some
|
||||
) flatten s"Can't add relay node $position $node"
|
||||
} inject node.mainline.size
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package lila.study
|
||||
|
||||
import chess.{ Color, Centis }
|
||||
import chess.format.pgn.{ Glyph, Tag, Tags }
|
||||
import chess.variant.Variant
|
||||
import chess.{ Color, Centis }
|
||||
import org.joda.time.DateTime
|
||||
|
||||
import chess.opening.{ FullOpening, FullOpeningDB }
|
||||
|
@ -22,6 +22,7 @@ case class Chapter(
|
|||
practice: Option[Boolean] = None,
|
||||
gamebook: Option[Boolean] = None,
|
||||
description: Option[String] = None,
|
||||
relayLastMoveAt: Option[DateTime] = None,
|
||||
createdAt: DateTime
|
||||
) extends Chapter.Like {
|
||||
|
||||
|
@ -30,9 +31,13 @@ case class Chapter(
|
|||
copy(root = newRoot)
|
||||
}
|
||||
|
||||
def addNode(node: Node, path: Path): Option[Chapter] =
|
||||
def addNode(node: Node, path: Path, relayMoveAt: Option[DateTime] = None): Option[Chapter] =
|
||||
updateRoot { root =>
|
||||
root.withChildren(_.addNodeAt(node, path))
|
||||
} map {
|
||||
_.copy(
|
||||
relayLastMoveAt = relayMoveAt orElse relayLastMoveAt
|
||||
)
|
||||
}
|
||||
|
||||
def setShapes(shapes: Shapes, path: Path): Option[Chapter] =
|
||||
|
@ -77,6 +82,10 @@ case class Chapter(
|
|||
def isConceal = conceal.isDefined
|
||||
|
||||
def withoutChildren = copy(root = root.withoutChildren)
|
||||
|
||||
def relaySecondsSinceLastMove: Option[Int] = relayLastMoveAt.map { at =>
|
||||
(nowSeconds - at.getSeconds).toInt
|
||||
}
|
||||
}
|
||||
|
||||
object Chapter {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package lila.study
|
||||
|
||||
import org.joda.time.DateTime
|
||||
import reactivemongo.api.ReadPreference
|
||||
|
||||
import lila.db.dsl._
|
||||
|
@ -59,6 +60,9 @@ final class ChapterRepo(coll: Coll) {
|
|||
def removeConceal(chapterId: Chapter.Id) =
|
||||
coll.unsetField($id(chapterId), "conceal").void
|
||||
|
||||
def setRelayLastMoveAt(chapterId: Chapter.Id, at: DateTime) =
|
||||
coll.updateField($id(chapterId), "relayLastMoveAt", at).void
|
||||
|
||||
def setTagsFor(chapter: Chapter) =
|
||||
coll.updateField($id(chapter.id), "tags", chapter.tags).void
|
||||
|
||||
|
|
|
@ -46,7 +46,8 @@ final class JsonView(
|
|||
"computer" -> allowed(study.settings.computer),
|
||||
"explorer" -> allowed(study.settings.explorer)
|
||||
)
|
||||
).add("description", currentChapter.description) |> addChapterMode(currentChapter)
|
||||
).add("description", currentChapter.description)
|
||||
.add("relaySecondsSinceLastMove", currentChapter.relaySecondsSinceLastMove) |> addChapterMode(currentChapter)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
|
@ -3,15 +3,17 @@ package lila.study
|
|||
import akka.actor._
|
||||
import play.api.libs.json._
|
||||
import scala.concurrent.duration._
|
||||
import org.joda.time.DateTime
|
||||
|
||||
import chess.format.pgn.Glyphs
|
||||
import chess.Centis
|
||||
import chess.format.pgn.Glyphs
|
||||
import lila.hub.TimeBomb
|
||||
import lila.socket.actorApi.{ Connected => _, _ }
|
||||
import lila.socket.Socket.Uid
|
||||
import lila.socket.{ SocketActor, History, Historical, AnaDests }
|
||||
import lila.tree.Node.{ Shapes, Comment }
|
||||
import lila.user.User
|
||||
import lila.common.PimpedJson._
|
||||
|
||||
private final class Socket(
|
||||
studyId: Study.Id,
|
||||
|
@ -293,7 +295,13 @@ object Socket {
|
|||
case class ReloadUid(uid: Uid)
|
||||
case class ReloadUidBecauseOf(uid: Uid, chapterId: Chapter.Id)
|
||||
|
||||
case class AddNode(position: Position.Ref, node: Node, variant: chess.variant.Variant, uid: Uid, sticky: Boolean)
|
||||
case class AddNode(
|
||||
position: Position.Ref,
|
||||
node: Node,
|
||||
variant: chess.variant.Variant,
|
||||
uid: Uid,
|
||||
sticky: Boolean
|
||||
)
|
||||
case class DeleteNode(position: Position.Ref, uid: Uid)
|
||||
case class Promote(position: Position.Ref, toMainline: Boolean, uid: Uid)
|
||||
case class SetPath(position: Position.Ref, uid: Uid)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package lila.study
|
||||
|
||||
import akka.actor.{ ActorRef, ActorSelection }
|
||||
import org.joda.time.DateTime
|
||||
import scala.concurrent.duration._
|
||||
|
||||
import chess.Centis
|
||||
|
@ -177,13 +178,13 @@ final class StudyApi(
|
|||
|
||||
def addNode(userId: User.ID, studyId: Study.Id, position: Position.Ref, node: Node, uid: Uid, opts: MoveOpts) = sequenceStudyWithChapter(studyId, position.chapterId) {
|
||||
case Study.WithChapter(study, chapter) => Contribute(userId, study) {
|
||||
doAddNode(userId, study, Position(chapter, position.path), node, uid, opts).void
|
||||
doAddNode(userId, study, Position(chapter, position.path), node, uid, opts, none).void
|
||||
}
|
||||
}
|
||||
|
||||
def doAddNode(userId: User.ID, study: Study, position: Position, rawNode: Node, uid: Uid, opts: MoveOpts): Fu[Option[Position]] = {
|
||||
def doAddNode(userId: User.ID, study: Study, position: Position, rawNode: Node, uid: Uid, opts: MoveOpts, relayMoveAt: Option[DateTime]): Fu[Option[Position]] = {
|
||||
val node = rawNode.withoutChildren
|
||||
position.chapter.addNode(node, position.path) match {
|
||||
position.chapter.addNode(node, position.path, relayMoveAt) match {
|
||||
case None =>
|
||||
fufail(s"Invalid addNode ${study.id} ${position.ref} $node") >>-
|
||||
reloadUidBecauseOf(study, uid, position.chapter.id) inject none
|
||||
|
@ -191,6 +192,7 @@ final class StudyApi(
|
|||
chapter.root.nodeAt(position.path) ?? { parent =>
|
||||
val newPosition = position.ref + node
|
||||
chapterRepo.setChildren(chapter, position.path, parent.children) >>
|
||||
(relayMoveAt ?? { chapterRepo.setRelayLastMoveAt(chapter.id, _) }) >>
|
||||
(opts.sticky ?? studyRepo.setPosition(study.id, newPosition)) >>
|
||||
updateConceal(study, chapter, newPosition) >>- {
|
||||
sendTo(study, Socket.AddNode(position.ref, node, chapter.setup.variant, uid, sticky = opts.sticky))
|
||||
|
|
|
@ -2,6 +2,10 @@ import AnalyseCtrl from './ctrl';
|
|||
import { h } from 'snabbdom'
|
||||
import { VNode } from 'snabbdom/vnode'
|
||||
|
||||
interface ClockOpts {
|
||||
tenths: boolean;
|
||||
}
|
||||
|
||||
export default function(ctrl: AnalyseCtrl): VNode | undefined {
|
||||
const node = ctrl.node, clock = node.clock;
|
||||
if (!clock && clock !== 0) return;
|
||||
|
@ -17,25 +21,28 @@ export default function(ctrl: AnalyseCtrl): VNode | undefined {
|
|||
blackCentis = parentClock;
|
||||
}
|
||||
const whitePov = ctrl.bottomColor() === 'white';
|
||||
const whiteEl = renderClock(whiteCentis, isWhiteTurn);
|
||||
const blackEl = renderClock(blackCentis, !isWhiteTurn);
|
||||
const opts = {
|
||||
tenths: !ctrl.study || !ctrl.study.relay
|
||||
};
|
||||
const whiteEl = renderClock(whiteCentis, isWhiteTurn, opts);
|
||||
const blackEl = renderClock(blackCentis, !isWhiteTurn, opts);
|
||||
|
||||
return h('div.aclocks', whitePov ? [blackEl, whiteEl] : [whiteEl, blackEl]);
|
||||
}
|
||||
|
||||
function renderClock(centis: number, active: boolean): VNode {
|
||||
function renderClock(centis: number, active: boolean, opts: ClockOpts): VNode {
|
||||
return h('div.aclock', {
|
||||
class: { active },
|
||||
}, clockContent(centis));
|
||||
}, clockContent(centis, opts));
|
||||
}
|
||||
|
||||
function clockContent(centis: number): Array<string | VNode> {
|
||||
function clockContent(centis: number, opts: ClockOpts): Array<string | VNode> {
|
||||
if (!centis && centis !== 0) return ['-'];
|
||||
const date = new Date(centis * 10),
|
||||
millis = date.getUTCMilliseconds(),
|
||||
sep = ':',
|
||||
baseStr = pad2(date.getUTCMinutes()) + sep + pad2(date.getUTCSeconds());
|
||||
if (centis >= 360000) return [Math.floor(centis / 360000) + sep + baseStr];
|
||||
if (!opts.tenths || centis >= 360000) return [Math.floor(centis / 360000) + sep + baseStr];
|
||||
const tenthsStr = Math.floor(millis / 100).toString();
|
||||
return [
|
||||
baseStr,
|
||||
|
|
Loading…
Reference in New Issue