Skip to content
Merged
21 changes: 13 additions & 8 deletions app/views/user/perfStat.scala
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ object perfStat:
div(cls := "box__pad perf-stat__content")(
glicko(user, perfType, user.perfs(perfType), percentile),
counter(stat.count),
highlow(stat),
highlow(stat, percentileLow, percentileHigh),
resultStreak(stat.resultStreak),
result(stat, user),
playStreakNb(stat.playStreak),
Expand Down Expand Up @@ -196,20 +196,25 @@ object perfStat:
)
)

private def highlowSide(title: Frag => Frag, opt: Option[lila.perfStat.RatingAt], color: String)(using
Lang
): Frag = opt match
private def highlowSide(
title: Frag => Frag,
opt: Option[lila.perfStat.RatingAt],
pctStr: Option[String],
color: String
)(using Lang): Frag = opt match
case Some(r) =>
div(
h2(title(strong(tag(color)(r.int)))),
h2(title(strong(tag(color)(r.int, pctStr.map(st.title := _))))),
a(cls := "glpt", href := routes.Round.watcher(r.gameId, "white"))(absClientInstant(r.at))
)
case None => div(h2(title(emptyFrag)), " ", span(notEnoughGames()))

private def highlow(stat: PerfStat)(using Lang): Frag =
private def highlow(stat: PerfStat, pctLow: Option[Double], pctHigh: Option[Double])(using Lang): Frag =
import stat.perfType
def titleOf(v: Double) = trans.betterThanPercentPlayers.txt(s"$v%", perfType.trans)
st.section(cls := "highlow split")(
highlowSide(highestRating(_), stat.highest, "green"),
highlowSide(lowestRating(_), stat.lowest, "red")
highlowSide(highestRating(_), stat.highest, pctHigh.map(titleOf), "green"),
highlowSide(lowestRating(_), stat.lowest, pctLow.map(titleOf), "red")
)

private def fromTo(s: lila.perfStat.Streak)(using Lang): Frag =
Expand Down
1 change: 1 addition & 0 deletions modules/i18n/src/main/I18nKeys.scala
Original file line number Diff line number Diff line change
Expand Up @@ -557,6 +557,7 @@ object I18nKeys:
val `yourPerfTypeRatingIsRating` = I18nKey("yourPerfTypeRatingIsRating")
val `youAreBetterThanPercentOfPerfTypePlayers` = I18nKey("youAreBetterThanPercentOfPerfTypePlayers")
val `userIsBetterThanPercentOfPerfTypePlayers` = I18nKey("userIsBetterThanPercentOfPerfTypePlayers")
val `betterThanPercentPlayers` = I18nKey("betterThanPercentPlayers")
val `youDoNotHaveAnEstablishedPerfTypeRating` = I18nKey("youDoNotHaveAnEstablishedPerfTypeRating")
val `yourRating` = I18nKey("yourRating")
val `cumulative` = I18nKey("cumulative")
Expand Down
21 changes: 15 additions & 6 deletions modules/perfStat/src/main/PerfStatApi.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ case class PerfStatData(
user: User.WithPerfs,
stat: PerfStat,
ranks: UserRankMap,
percentile: Option[Double]
percentile: Option[Double],
percentileLow: Option[Double],
percentileHigh: Option[Double]
):
def rank = ranks get stat.perfType

Expand All @@ -30,16 +32,23 @@ final class PerfStatApi(
!u.isBot || (perfType =!= PerfType.UltraBullet)
.soFu: u =>
for

oldPerfStat <- get(u.user, perfType)
perfStat = oldPerfStat.copy(playStreak = oldPerfStat.playStreak.checkCurrent)

distribution <- u.perfs(perfType).established soFu rankingApi.weeklyRatingDistribution(perfType)
percentile = distribution.map: distrib =>
val (under, sum) = lila.user.Stat.percentile(distrib, u.perfs(perfType).intRating)
Math.round(under * 1000.0 / sum) / 10.0
_ = lightUserApi preloadUser u.user
percentile = calcPercentile(distribution, u.perfs(perfType).intRating)
percentileLow = perfStat.lowest.flatMap { r => calcPercentile(distribution, r.int) }
percentileHigh = perfStat.highest.flatMap { r => calcPercentile(distribution, r.int) }
_ = lightUserApi preloadUser u.user
_ <- lightUserApi preloadMany perfStat.userIds
yield PerfStatData(u, perfStat, rankingsOf(u.id), percentile)
yield PerfStatData(u, perfStat, rankingsOf(u.id), percentile, percentileLow, percentileHigh)
}

private def calcPercentile(wrd: Option[List[Int]], intRating: IntRating): Option[Double] =
wrd.map: distrib =>
val (under, sum) = lila.user.Stat.percentile(distrib, intRating)
Math.round(under * 1000.0 / sum) / 10.0

def get(user: User, perfType: PerfType): Fu[PerfStat] =
storage.find(user.id, perfType) getOrElse indexer.userPerf(user, perfType)
1 change: 1 addition & 0 deletions translation/source/site.xml
Original file line number Diff line number Diff line change
Expand Up @@ -707,6 +707,7 @@ computer analysis, game chat and shareable URL.</string>
<string name="yourPerfTypeRatingIsRating">Your %1$s rating is %2$s.</string>
<string name="youAreBetterThanPercentOfPerfTypePlayers">You are better than %1$s of %2$s players.</string>
<string name="userIsBetterThanPercentOfPerfTypePlayers">%1$s is better than %2$s of %3$s players.</string>
<string name="betterThanPercentPlayers">Better than %1$s of %2$s players</string>
<string name="youDoNotHaveAnEstablishedPerfTypeRating">You do not have an established %s rating.</string>
<string name="yourRating">Your rating</string>
<string name="cumulative">Cumulative</string>
Expand Down