activity UI WIP

pull/3314/merge
Thibault Duplessis 2017-07-19 22:37:50 +02:00
parent 92c7a5a001
commit 0a1e8c7637
9 changed files with 140 additions and 5 deletions

View File

@ -12,8 +12,8 @@ import lila.common.paginator.Paginator
import lila.common.{ IpAddress, HTTPRequest }
import lila.game.{ GameRepo, Game => GameModel }
import lila.rating.PerfType
import lila.user.{ User => UserModel, UserRepo }
import lila.socket.UserLagCache
import lila.user.{ User => UserModel, UserRepo }
import views._
object User extends LilaController {
@ -322,4 +322,12 @@ object User extends LilaController {
def myself = Auth { ctx => me =>
fuccess(Redirect(routes.User.show(me.username)))
}
def activity(username: String) = Open { implicit ctx =>
OptionFuResult(UserRepo named username) { user =>
Env.activity.read.recent(user.id, 3) map { as =>
Ok(html.activity.list(user, as))
}
}
}
}

View File

@ -0,0 +1,23 @@
package views.html.activity
import play.twirl.api.Html
import lila.activity.activities._
import lila.activity.model._
import lila.api.Context
import lila.i18n.{ I18nKey, I18nKeys => trans }
object ActivityHtml extends lila.Steroids {
def scoreHtml(s: Score)(implicit ctx: Context) = Html {
s"""<score>${scorePart("win", s.win, trans.nbWins)}${scorePart("draw", s.draw, trans.nbDraws)}${scorePart("loss", s.loss, trans.nbLosses)}</score>"""
}
private def scorePart(tag: String, p: Int, name: I18nKey)(implicit ctx: Context) =
if (p == 0) ""
else s"""<$tag>${wrapNumber(name.pluralSameTxt(p))}</$tag>"""
private val wrapNumberRegex = """(\d+)""".r
private def wrapNumber(str: String) =
wrapNumberRegex.replaceAllIn(str, "<strong>$1</strong>")
}

View File

@ -0,0 +1,47 @@
@(u: User, as: List[lila.activity.ActivityView.AsTo])(implicit ctx: Context)
@import ActivityHtml._
@moreCss = {
@cssTag("activity.css")
}
@user.layout(
title = s"${u.username} activity",
evenMoreCss = moreCss) {
<div class="content_box no_padding activity">
<div class="content_box_top">
<h1 class="lichess_title">
<a href="@routes.User.show(u.username)">
@u.username activity
</a>
</h1>
</div>
<div class="timeline">
@as.map {
case lila.activity.ActivityView.AsTo(date, a) => {
<section>
<h2>@semanticDate(date)</h2>
@defining(a.puzzles) { p =>
<div class="entry puzzles">
<strong>Played @p.score.size tactical puzzles</strong>
@scoreHtml(p.score)
</div>
}
@a.games.value.map {
case (pt, score) => {
<div class="entry games">
<strong>Played @score.size @pt.name games</strong>
@scoreHtml(score)
</div>
}
}
</section>
}
}
</div>
</h1>
</div>
<div class="content_box_content">right here.</div>
</div>
}

View File

@ -55,6 +55,7 @@ GET /@/:username/mod controllers.User.mod(username: String)
POST /@/:username/note controllers.User.writeNote(username: String)
GET /@/:username/mini controllers.User.showMini(username: String)
GET /@/:username/tv controllers.User.tv(username: String)
GET /@/:username/activity controllers.User.activity(username: String)
GET /@/:username/studyTv controllers.User.studyTv(username: String)
GET /@/:username/perf/:perfKey controllers.User.perfStat(username: String, perfKey: String)
GET /@/:username/:filterName controllers.User.showFilter(username: String, filterName: String, page: Int ?= 1)

View File

@ -18,8 +18,7 @@ case class Activity(
corres: Corres
) {
def userId = id.userId
def day = id.day
def date = Activity.Day.genesis plusDays id.day.value
}
object Activity {
@ -36,6 +35,9 @@ object Activity {
object Day {
val genesis = new DateTime(2010, 1, 1, 0, 0).withTimeAtStartOfDay
def today = Day(Days.daysBetween(genesis, DateTime.now.withTimeAtStartOfDay).getDays)
def recent(nb: Int): List[Day] = (0 to (nb - 1)).toList.map { delta =>
Day(Days.daysBetween(genesis, DateTime.now.minusDays(delta).withTimeAtStartOfDay).getDays)
}
}
def make(userId: User.ID) = Activity(

View File

@ -12,5 +12,16 @@ final class ActivityReadApi(coll: Coll) {
import BSONHandlers._
import activities._
def get(userId: User.ID) = coll.byId[Activity, Id](Id today userId)
def recent(userId: User.ID, days: Int): Fu[List[ActivityView.AsTo]] =
coll.find($inIds(makeIds(userId, days))).list[Activity]() map { as =>
as.map { a =>
ActivityView.AsTo(
a.pp.date,
ActivityView(a.games, a.puzzles)
)
}
}
private def makeIds(userId: User.ID, days: Int): List[Id] =
Day.recent(days).map { Id(userId, _) }
}

View File

@ -0,0 +1,18 @@
package lila.activity
import org.joda.time.DateTime
import lila.user.User
import activities._
case class ActivityView(
games: Games,
puzzles: Puzzles
) {
}
object ActivityView {
case class AsTo(day: DateTime, activity: ActivityView)
}

View File

@ -25,4 +25,4 @@ object Insight {
case class Stacked(points: List[(Metric.MetricValueName, Point)]) extends Insight
}
case class Point(y: Double)
case class Point(y: Double) extends AnyVal

View File

@ -0,0 +1,25 @@
.activity section::before {
position: absolute;
top: 0;
bottom: 0;
left: 15px;
z-index: -1;
display: block;
width: 2px;
content: "";
background-color: #e6ebf1;
}
.activity section h2 {
font-weight: bold;
}
.activity .entry {
padding: 20px;
}
.activity .entry strong {
font-weight: normal;
}
.activity .score {
float: right;
}
.activity .score strong {
}