complete user preferences w/ automatic queen option
This commit is contained in:
parent
54216e0d56
commit
fa4b11f0a1
|
@ -27,7 +27,7 @@ object Environment
|
|||
with PaginatorHelper
|
||||
with FormHelper
|
||||
with SetupHelper
|
||||
with PrefHelper
|
||||
with lila.pref.PrefHelper
|
||||
with MessageHelper
|
||||
with lila.round.RoundHelper
|
||||
with AiHelper
|
||||
|
|
|
@ -5,11 +5,11 @@ import lila.message.Env.{ current ⇒ messageEnv }
|
|||
import lila.report.Env.{ current ⇒ reportEnv }
|
||||
import lila.user.Context
|
||||
|
||||
trait MessageHelper { self: SecurityHelper =>
|
||||
trait MessageHelper { self: SecurityHelper ⇒
|
||||
|
||||
def messageNbUnread(ctx: Context): Int =
|
||||
ctx.me.??(user ⇒ messageEnv.api.unreadIds(user.id).await.size)
|
||||
|
||||
def reportNbUnprocessed(implicit ctx: Context): Int =
|
||||
def reportNbUnprocessed(implicit ctx: Context): Int =
|
||||
isGranted(_.SeeReport) ?? reportEnv.api.nbUnprocessed.await
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
@(field: Field, label: String)(implicit ctx: Context)
|
||||
|
||||
<li>
|
||||
<li class="field">
|
||||
<label for="@field.id">@label</label>
|
||||
<input
|
||||
class="passwd"
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
@(u: User, form: Form[_])(implicit ctx: Context)
|
||||
|
||||
@import lila.pref.Pref
|
||||
|
||||
@title = @{ s"${u.username} - ${trans.preferences.str()}" }
|
||||
|
||||
@evenMoreCss = {
|
||||
|
@ -10,16 +12,12 @@
|
|||
<div class="content_box small_box">
|
||||
<div class="signup_box">
|
||||
<h1 class="lichess_title">@trans.preferences()</h1>
|
||||
<form action="@routes.Account.profileApply" method="POST">
|
||||
<form action="@routes.Pref.formApply" method="POST">
|
||||
<ul>
|
||||
<li>
|
||||
@base.checkbox(form("chat"), "Enable chat rooms", 1)
|
||||
</li>
|
||||
<li>
|
||||
@base.checkbox(form("sound"), "Enable sound", 1)
|
||||
</li>
|
||||
<li>
|
||||
@errMsg(form)
|
||||
<li class="field">
|
||||
<label for="@form("autoQueen").id">Promotion</label>
|
||||
@base.select(form("autoQueen"), Pref.AutoQueen.choices)
|
||||
<p class="help">Automatic promotion or manual choice?</p>
|
||||
</li>
|
||||
<li>
|
||||
<input type="submit" class="submit button" value="@trans.apply()" />
|
||||
|
|
|
@ -13,26 +13,26 @@
|
|||
<p>All informations are public and optional.</p>
|
||||
<form action="@routes.Account.profileApply" method="POST">
|
||||
<ul>
|
||||
<li>
|
||||
<li class="field">
|
||||
<label for="@form("country").id">@trans.country()</label>
|
||||
@base.select(form("country"), lila.user.Countries.all, default = "".some)
|
||||
</li>
|
||||
<li>
|
||||
<li class="field">
|
||||
<label for="@form("location").id">@trans.location()</label>
|
||||
@base.input(form("location"))
|
||||
<p class="help">Your city, region, or department.</p>
|
||||
</li>
|
||||
<li>
|
||||
<li class="field">
|
||||
<label for="@form("bio").id">@trans.biography()</label>
|
||||
<textarea name="@form("bio").name" id="@form("bio").id" cols="25" rows="7">@form("bio").value</textarea>
|
||||
<p class="help">Tell about you, what you like in chess, your favorite openings, games, players...</p>
|
||||
<p class="help">Maximum: 400 characters.</p>
|
||||
</li>
|
||||
<li>
|
||||
<li class="field">
|
||||
<label for="@form("firstName").id">@trans.firstName()</label>
|
||||
@base.input(form("firstName"))
|
||||
</li>
|
||||
<li>
|
||||
<li class="field">
|
||||
<label for="@form("lastName").id">@trans.lastName()</label>
|
||||
@base.input(form("lastName"))
|
||||
</li>
|
||||
|
|
|
@ -8,24 +8,20 @@ import lila.user.User
|
|||
private[pref] final class DataForm(api: PrefApi) {
|
||||
|
||||
val pref = Form(mapping(
|
||||
"chat" -> boolean,
|
||||
"sound" -> boolean
|
||||
"autoQueen" -> number.verifying(Pref.AutoQueen.choices.toMap contains _)
|
||||
)(PrefData.apply)(PrefData.unapply))
|
||||
|
||||
case class PrefData(
|
||||
chat: Boolean,
|
||||
sound: Boolean) {
|
||||
autoQueen: Int) {
|
||||
|
||||
def apply(pref: Pref) = pref.copy(
|
||||
chat = chat,
|
||||
sound = sound)
|
||||
autoQueen = autoQueen)
|
||||
}
|
||||
|
||||
object PrefData {
|
||||
|
||||
def apply(pref: Pref): PrefData = PrefData(
|
||||
chat = pref.chat,
|
||||
sound = pref.sound)
|
||||
autoQueen = pref.autoQueen)
|
||||
}
|
||||
|
||||
def prefOf(user: User): Fu[Form[PrefData]] = api getPref user map { p ⇒
|
||||
|
|
|
@ -5,26 +5,20 @@ import scala._
|
|||
case class Pref(
|
||||
id: String, // user id
|
||||
dark: Boolean,
|
||||
chat: Boolean,
|
||||
sound: Boolean,
|
||||
theme: String) {
|
||||
theme: String,
|
||||
autoQueen: Int) {
|
||||
|
||||
def realTheme = Theme(theme)
|
||||
def toggleDark = copy(dark = !dark)
|
||||
def toggleChat = copy(chat = !chat)
|
||||
def toggleSound = copy(sound = !sound)
|
||||
|
||||
def get(name: String): Option[String] = name match {
|
||||
case "dark" ⇒ dark.toString.some
|
||||
case "chat" ⇒ chat.toString.some
|
||||
case "sound" ⇒ sound.toString.some
|
||||
case "theme" ⇒ theme.some
|
||||
case _ ⇒ none
|
||||
}
|
||||
def set(name: String, value: String): Option[Pref] = name match {
|
||||
case "dark" ⇒ Pref.booleans get value map { b ⇒ copy(dark = b) }
|
||||
case "chat" ⇒ Pref.booleans get value map { b ⇒ copy(chat = b) }
|
||||
case "sound" ⇒ Pref.booleans get value map { b ⇒ copy(sound = b) }
|
||||
case "bg" ⇒ Pref.bgs get value map { b ⇒ copy(dark = b) }
|
||||
case "theme" ⇒ Theme.allByName get value map { t ⇒ copy(theme = t.name) }
|
||||
case _ ⇒ none
|
||||
}
|
||||
|
@ -32,14 +26,27 @@ case class Pref(
|
|||
|
||||
object Pref {
|
||||
|
||||
val default = Pref(
|
||||
id = "",
|
||||
object AutoQueen {
|
||||
val NEVER = 1
|
||||
val PREMOVE = 2
|
||||
val ALWAYS = 3
|
||||
|
||||
val choices = Seq(
|
||||
NEVER -> "Always choose manually",
|
||||
PREMOVE -> "Automatic queen on premove",
|
||||
ALWAYS -> "Always automatic queen")
|
||||
}
|
||||
|
||||
def create(id: String) = Pref(
|
||||
id = id,
|
||||
dark = false,
|
||||
chat = true,
|
||||
sound = false,
|
||||
theme = Theme.default.name)
|
||||
theme = Theme.default.name,
|
||||
autoQueen = AutoQueen.PREMOVE)
|
||||
|
||||
val default = create("")
|
||||
|
||||
private val booleans = Map("true" -> true, "false" -> false)
|
||||
private val bgs = Map("light" -> false, "dark" -> true)
|
||||
|
||||
import lila.db.Tube
|
||||
import Tube.Helpers._
|
||||
|
@ -52,7 +59,6 @@ object Pref {
|
|||
|
||||
private def defaults = Json.obj(
|
||||
"dark" -> default.dark,
|
||||
"chat" -> default.chat,
|
||||
"sound" -> default.sound,
|
||||
"theme" -> default.theme)
|
||||
"theme" -> default.theme,
|
||||
"autoQueen" -> default.autoQueen)
|
||||
}
|
||||
|
|
|
@ -1,24 +1,25 @@
|
|||
package lila.pref
|
||||
|
||||
import lila.db.api._
|
||||
import lila.user.User
|
||||
import tube.prefTube
|
||||
import lila.db.api._
|
||||
|
||||
final class PrefApi {
|
||||
|
||||
def getPref(id: String): Fu[Pref] = $find byId id map (_ | Pref.default)
|
||||
def getPref(id: String): Fu[Pref] = $find byId id map (_ | Pref.create(id))
|
||||
def getPref(user: User): Fu[Pref] = getPref(user.id)
|
||||
|
||||
def getPref[A](user: User, pref: Pref ⇒ A): Fu[A] = getPref(user) map pref
|
||||
|
||||
def getPrefString(user: User, name: String): Fu[Option[String]] =
|
||||
def getPrefString(user: User, name: String): Fu[Option[String]] =
|
||||
getPref(user) map (_ get name)
|
||||
|
||||
def setPref(pref: Pref): Funit = $update(pref)
|
||||
def setPref(pref: Pref): Funit = $save(pref)
|
||||
|
||||
def setPref(user: User, change: Pref ⇒ Pref): Funit =
|
||||
def setPref(user: User, change: Pref ⇒ Pref): Funit =
|
||||
getPref(user) map change flatMap setPref
|
||||
|
||||
def setPrefString(user: User, name: String, value: String): Funit =
|
||||
getPref(user) map (_ get name)
|
||||
def setPrefString(user: User, name: String, value: String): Funit =
|
||||
getPref(user) map { _.set(name, value) } flatten
|
||||
s"Bad pref ${user.id} $name -> $value" flatMap setPref
|
||||
}
|
||||
|
|
|
@ -1,23 +1,23 @@
|
|||
package lila.app
|
||||
package templating
|
||||
package lila.pref
|
||||
|
||||
import lila.pref.Env.{ current ⇒ env }
|
||||
import lila.user.Context
|
||||
import lila.pref.Theme
|
||||
import lila.pref.Env.{ current ⇒ prevEnv }
|
||||
|
||||
import play.api.templates.Html
|
||||
|
||||
trait PrefHelper {
|
||||
|
||||
private def get(name: String)(implicit ctx: Context): Option[String] =
|
||||
private def get(name: String)(implicit ctx: Context): Option[String] =
|
||||
ctx.req.session get name orElse {
|
||||
ctx.me ?? { prevEnv.api.getPrefString(_, name) }
|
||||
}.await
|
||||
ctx.me ?? { env.api.getPrefString(_, name) }
|
||||
}.await
|
||||
|
||||
def currentTheme(implicit ctx: Context): Theme = Theme(~get("theme"))
|
||||
|
||||
def currentBg(implicit ctx: Context): String =
|
||||
def currentBg(implicit ctx: Context): String =
|
||||
if (get("dark") == Some("true")) "dark" else "light"
|
||||
|
||||
def userPref(implicit ctx: Context): Pref = {
|
||||
ctx.me.fold(fuccess(Pref.default))(env.api.getPref)
|
||||
}.await
|
||||
|
||||
def themeList = Theme.list
|
||||
}
|
|
@ -110,7 +110,10 @@ final class Env(
|
|||
roundMap = roundMap,
|
||||
socketHub = socketHub)
|
||||
|
||||
lazy val messenger = new Messenger(NetDomain, i18nKeys, getUsername)
|
||||
lazy val messenger = new Messenger(
|
||||
netDomain = NetDomain,
|
||||
i18nKeys = i18nKeys,
|
||||
getUsername = getUsername)
|
||||
|
||||
lazy val eloCalculator = new chess.EloCalculator(false)
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package lila.round
|
||||
|
||||
import chess.Color
|
||||
import org.apache.commons.lang3.StringEscapeUtils.escapeXml
|
||||
|
||||
import chess.Color
|
||||
import lila.db.api._
|
||||
import lila.game.Event
|
||||
import lila.game.{ Game, PovRef, Namer }
|
||||
|
@ -21,16 +21,7 @@ final class Messenger(
|
|||
def init(game: Game): Fu[List[Event]] = systemMessages(game, List(
|
||||
game.creatorColor.fold(_.whiteCreatesTheGame, _.blackCreatesTheGame),
|
||||
game.invitedColor.fold(_.whiteJoinsTheGame, _.blackJoinsTheGame)
|
||||
)) flatMap { events ⇒
|
||||
(Color.all map { color ⇒
|
||||
(game player color).userId ?? { id ⇒
|
||||
UserRepo.getSetting(id, "chat") flatMap {
|
||||
case Some("false") ⇒ toggleChat(PovRef(game.id, color), false)
|
||||
case _ ⇒ fuccess(Nil)
|
||||
}
|
||||
}
|
||||
}).sequenceFu map { events ::: _.flatten }
|
||||
}
|
||||
))
|
||||
|
||||
// copies chats then init
|
||||
// no need to send events back
|
||||
|
@ -80,16 +71,6 @@ final class Messenger(
|
|||
}
|
||||
}
|
||||
|
||||
def toggleChat(ref: PovRef, status: Boolean): Fu[List[Event]] =
|
||||
"%s chat is %s".format(
|
||||
ref.color.toString.capitalize,
|
||||
status.fold("en", "dis") + "abled"
|
||||
) |> { message ⇒
|
||||
RoomRepo.addSystemMessage(ref.gameId, message) inject {
|
||||
Event.Message("system", message, false) :: Nil
|
||||
}
|
||||
}
|
||||
|
||||
private def trans(message: SelectI18nKey, args: Any*): String =
|
||||
message(i18nKeys).en(args: _*)
|
||||
}
|
||||
|
|
|
@ -1,19 +1,21 @@
|
|||
package lila.round
|
||||
|
||||
import lila.user.Context
|
||||
import lila.game.Pov
|
||||
import lila.round.Env.{ current ⇒ roundEnv }
|
||||
|
||||
import play.api.libs.json.Json
|
||||
import scala.math.{ min, max, round }
|
||||
|
||||
trait RoundHelper {
|
||||
import play.api.libs.json.Json
|
||||
|
||||
import lila.game.Pov
|
||||
import lila.pref.PrefHelper
|
||||
import lila.round.Env.{ current ⇒ roundEnv }
|
||||
import lila.user.Context
|
||||
|
||||
trait RoundHelper { self: PrefHelper ⇒
|
||||
|
||||
def moretimeSeconds = roundEnv.moretimeSeconds
|
||||
|
||||
def gameAnimationDelay = roundEnv.animationDelay
|
||||
|
||||
def roundPlayerJsData(pov: Pov, version: Int) = {
|
||||
def roundPlayerJsData(pov: Pov, version: Int)(implicit ctx: Context) = {
|
||||
import pov._
|
||||
Json.obj(
|
||||
"game" -> Json.obj(
|
||||
|
@ -37,6 +39,7 @@ trait RoundHelper {
|
|||
),
|
||||
"possible_moves" -> possibleMoves(pov),
|
||||
"animation_delay" -> animationDelay(pov),
|
||||
"autoQueen" -> userPref.autoQueen,
|
||||
"tournament_id" -> game.tournamentId
|
||||
)
|
||||
}
|
||||
|
|
|
@ -75,8 +75,6 @@ private[round] final class SocketHandler(
|
|||
case ("moretime", _) ⇒ round(Moretime(playerId))
|
||||
case ("outoftime", _) ⇒ round(Outoftime)
|
||||
case ("bye", _) ⇒ socket ! Bye(ref.color)
|
||||
case ("toggle-chat", o) ⇒
|
||||
messenger.toggleChat(ref, ~(o boolean "d")) pipeTo socket
|
||||
case ("challenge", o) ⇒ ((o str "d") |@| member.userId).tupled foreach {
|
||||
case (to, from) ⇒ hub.actor.challenger ! lila.hub.actorApi.setup.RemindChallenge(gameId, from, to)
|
||||
}
|
||||
|
|
|
@ -15,7 +15,6 @@ case class User(
|
|||
ipBan: Boolean = false,
|
||||
enabled: Boolean,
|
||||
roles: List[String],
|
||||
settings: Map[String, String] = Map.empty,
|
||||
profile: Option[Profile] = None,
|
||||
engine: Boolean = false,
|
||||
toints: Int = 0,
|
||||
|
@ -38,8 +37,6 @@ case class User(
|
|||
|
||||
def usernameWithElo = "%s (%d)".format(username, elo)
|
||||
|
||||
def setting(name: String): Option[Any] = settings get name
|
||||
|
||||
def profileOrDefault = profile | Profile.default
|
||||
|
||||
def hasGames = count.game > 0
|
||||
|
@ -85,7 +82,6 @@ object User {
|
|||
"variantElos" -> VariantElos.default,
|
||||
"troll" -> false,
|
||||
"ipBan" -> false,
|
||||
"settings" -> Json.obj(),
|
||||
"engine" -> false,
|
||||
"toints" -> 0,
|
||||
"roles" -> Json.arr(),
|
||||
|
|
|
@ -68,7 +68,6 @@ object UserRepo {
|
|||
|
||||
def setProfile(id: ID, profile: Profile): Funit = {
|
||||
import tube.profileTube
|
||||
println(profile)
|
||||
profile.nonEmpty match {
|
||||
case Some(p) => $update($select(id), $set("profile" -> p))
|
||||
case None => $update($select(id), $unset("profile"))
|
||||
|
@ -109,14 +108,6 @@ object UserRepo {
|
|||
elos.sum / elos.size.toFloat
|
||||
}
|
||||
|
||||
def saveSetting(id: ID, key: String, value: String): Funit =
|
||||
$update($select(id), $set(("settings." + key) -> value))
|
||||
|
||||
def getSetting(id: ID, key: String): Fu[Option[String]] =
|
||||
$primitive.one($select(id), "settings") {
|
||||
_.asOpt[Map[String, String]] flatMap (_ get key)
|
||||
}
|
||||
|
||||
def authenticate(id: ID, password: String): Fu[Option[User]] =
|
||||
checkPassword(id, password) flatMap { _ ?? ($find byId id) }
|
||||
|
||||
|
|
|
@ -88,7 +88,7 @@ object ApplicationBuild extends Build {
|
|||
)
|
||||
|
||||
lazy val round = project("round", Seq(
|
||||
common, db, memo, hub, socket, chess, game, user, security, i18n, ai)).settings(
|
||||
common, db, memo, hub, socket, chess, game, user, security, i18n, ai, pref)).settings(
|
||||
libraryDependencies ++= provided(play.api, reactivemongo, playReactivemongo)
|
||||
)
|
||||
|
||||
|
|
|
@ -827,10 +827,7 @@ var storage = {
|
|||
} else {
|
||||
return '<li class="' + u + (u == 'system' ? ' trans_me' : '') + '">' + urlToLink(t) + '</li>';
|
||||
}
|
||||
},
|
||||
onToggle: self.options.player.spectator ? function(e) {} : _.throttle(function(enabled) {
|
||||
lichess.socket.send("toggle-chat", enabled);
|
||||
}, 5000)
|
||||
}
|
||||
});
|
||||
}
|
||||
self.$watchers.watchers();
|
||||
|
@ -1241,7 +1238,8 @@ var storage = {
|
|||
var color = self.options.player.color;
|
||||
// promotion
|
||||
if ($piece.hasClass('pawn') && ((color == "white" && squareId[1] == 8) || (color == "black" && squareId[1] == 1))) {
|
||||
if (isPremove || false) {
|
||||
var aq = self.options.autoQueen;
|
||||
if (aq == 3 || (isPremove && aq == 2)) {
|
||||
moveData.promotion = "queen";
|
||||
sendMoveRequest(moveData);
|
||||
} else {
|
||||
|
@ -1552,7 +1550,6 @@ var storage = {
|
|||
_create: function() {
|
||||
this.options = $.extend({
|
||||
// render: function(u, t) {},
|
||||
onToggle: function(enabled) {},
|
||||
talkMessageType: 'talk',
|
||||
secure: false,
|
||||
resize: false
|
||||
|
@ -1595,7 +1592,6 @@ var storage = {
|
|||
$toggle.change(function() {
|
||||
var enabled = $toggle.is(':checked');
|
||||
self.element.toggleClass('hidden', !enabled);
|
||||
self.options.onToggle(enabled);
|
||||
if (!enabled) storage.set('nochat', 1);
|
||||
else storage.remove('nochat');
|
||||
});
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
list-style: none outside none;
|
||||
margin: 1em 0;
|
||||
}
|
||||
.content_box form label {
|
||||
.content_box form .field label {
|
||||
display: block;
|
||||
float: left;
|
||||
margin-right: 10px;
|
||||
|
@ -14,11 +14,6 @@
|
|||
text-align: right;
|
||||
width: 150px;
|
||||
}
|
||||
.content_box form input[type="text"] {
|
||||
border: 1px solid #D4D4D4;
|
||||
padding: 3px 5px;
|
||||
width: 200px;
|
||||
}
|
||||
.content_box form input.submit {
|
||||
margin-left: 160px;
|
||||
margin-right: 20px;
|
||||
|
|
7
todo
7
todo
|
@ -73,7 +73,12 @@ no challenge when playing http://en.lichess.org/forum/lichess-feedback/defis#2
|
|||
user option for auto-promotion (requested by NM :P) (http://en.lichess.org/@/Matetricks)
|
||||
check filter games icon on windows
|
||||
people page = trends by day, week, month. user achievments?
|
||||
user options: tenth of seconds, sounds, sound choice
|
||||
user options: tenth of seconds, premove, prepromotion, sounds, sound choice
|
||||
user stats: http://en.lichess.org/forum/lichess-feedback/feature-request-extended-stats
|
||||
forum improvements http://en.lichess.org/forum/lichess-feedback/suggestions-for-the-forum#1
|
||||
analysis 64... Kg6 should be blunder, not mistake
|
||||
|
||||
DEPLOY
|
||||
------ order matters
|
||||
mongo lichess bin/mongodb/pref.js
|
||||
mongo lichess bin/mongodb/user3.js
|
||||
|
|
Loading…
Reference in a new issue