diff --git a/src/gui b/src/gui index 24e94d10..f2760218 160000 --- a/src/gui +++ b/src/gui @@ -1 +1 @@ -Subproject commit 24e94d10e2ef2e34a6feb2bc8f9eca268260f512 +Subproject commit f2760218ef065f1cde53b801b184cfe02f24dff0 diff --git a/src/modules/statistics/graphics/stats.py b/src/modules/statistics/graphics/stats.py index ffa19bb0..5a093db1 100644 --- a/src/modules/statistics/graphics/stats.py +++ b/src/modules/statistics/graphics/stats.py @@ -6,11 +6,28 @@ import discord from meta import LionBot from gui.cards import StatsCard from gui.base import CardMode +from tracking.text.data import TextTrackerData +from .. import babel from ..data import StatsData +_p = babel._p + + +def format_time(seconds): + return "{:02}:{:02}".format( + int(seconds // 3600), + int(seconds % 3600 // 60) + ) + + +def format_xp(messages, xp): + return f"{messages} ({xp} XP)" + + async def get_stats_card(bot: LionBot, userid: int, guildid: int, mode: CardMode): + t = bot.translator.t data: StatsData = bot.get_cog('StatsCog').data # TODO: Workouts @@ -32,28 +49,41 @@ async def get_stats_card(bot: LionBot, userid: int, guildid: int, mode: CardMode ) # Extract the study times for each period - if mode in (CardMode.STUDY, CardMode.VOICE): + if mode in (CardMode.STUDY, CardMode.VOICE, CardMode.ANKI): model = data.VoiceSessionStats refkey = (guildid or None, userid) ref_since = model.study_times_since ref_between = model.study_times_between + + period_activity = await ref_since(*refkey, *period_timestamps) + period_strings = [format_time(activity) for activity in reversed(period_activity)] + month_activity = period_activity[1] + month_string = t(_p( + 'gui:stats|mode:voice|month', + "{hours} hours" + )).format(hours=int(month_activity // 3600)) elif mode is CardMode.TEXT: + msgmodel = TextTrackerData.TextSessions if guildid: model = data.MemberExp + msg_since = msgmodel.member_messages_since refkey = (guildid, userid) else: model = data.UserExp + msg_since = msgmodel.member_messages_between refkey = (userid,) ref_since = model.xp_since ref_between = model.xp_between - else: - # TODO ANKI - model = data.VoiceSessionStats - refkey = (guildid, userid) - ref_since = model.study_times_since - ref_between = model.study_times_between - study_times = await ref_since(*refkey, *period_timestamps) + xp_period_activity = await ref_since(*refkey, *period_timestamps) + msg_period_activity = await msg_since(*refkey, *period_timestamps) + period_strings = [ + format_xp(msgs, xp) + for msgs, xp in zip(reversed(msg_period_activity), reversed(xp_period_activity)) + ] + month_string = f"{xp_period_activity[1]} XP" + else: + raise ValueError(f"Mode {mode} not supported") # Get leaderboard position # TODO: Efficiency @@ -89,7 +119,8 @@ async def get_stats_card(bot: LionBot, userid: int, guildid: int, mode: CardMode card = StatsCard( (position, 0), - list(reversed(study_times)), + period_strings, + month_string, 100, streaks, skin={'mode': mode} diff --git a/src/tracking/text/data.py b/src/tracking/text/data.py index 61486923..ec75f197 100644 --- a/src/tracking/text/data.py +++ b/src/tracking/text/data.py @@ -288,6 +288,42 @@ class TextTrackerData(Registry): tuple(chain((userid, guildid), points)) ) return [r['messages'] or 0 for r in await cursor.fetchall()] + + @classmethod + @log_wrap(action='user_messages_since') + async def user_messages_since(cls, userid: int, *points): + """ + Compute messages written between the given points. + """ + query = sql.SQL( + """ + SELECT + ( + SELECT + SUM(messages) + FROM text_sessions s + WHERE + s.userid = %s + AND s.start_time >= t._start + ) AS messages + FROM + (VALUES {}) + AS + t (_start) + ORDER BY t._start + """ + ).format( + sql.SQL(', ').join( + sql.SQL("({})").format(sql.Placeholder()) for _ in points + ) + ) + async with cls._connector.connection() as conn: + async with conn.cursor() as cursor: + await cursor.execute( + query, + tuple(chain((userid,), points)) + ) + return [r['messages'] or 0 for r in await cursor.fetchall()] @classmethod @log_wrap(action='msgs_leaderboard_all')