diff --git a/app/views/user/perfStat.scala b/app/views/user/perfStat.scala index 763eeff4bddf5..5b512128bc765 100644 --- a/app/views/user/perfStat.scala +++ b/app/views/user/perfStat.scala @@ -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), @@ -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 = diff --git a/modules/i18n/src/main/I18nKeys.scala b/modules/i18n/src/main/I18nKeys.scala index af00557fdb37e..331c3425378e7 100644 --- a/modules/i18n/src/main/I18nKeys.scala +++ b/modules/i18n/src/main/I18nKeys.scala @@ -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") diff --git a/modules/perfStat/src/main/PerfStatApi.scala b/modules/perfStat/src/main/PerfStatApi.scala index 79ef78289127a..e9346e9c3e474 100644 --- a/modules/perfStat/src/main/PerfStatApi.scala +++ b/modules/perfStat/src/main/PerfStatApi.scala @@ -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 @@ -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) diff --git a/translation/source/site.xml b/translation/source/site.xml index 8d363d28c9dac..7567e29f08de2 100644 --- a/translation/source/site.xml +++ b/translation/source/site.xml @@ -707,6 +707,7 @@ computer analysis, game chat and shareable URL. Your %1$s rating is %2$s. You are better than %1$s of %2$s players. %1$s is better than %2$s of %3$s players. + Better than %1$s of %2$s players You do not have an established %s rating. Your rating Cumulative