elkay frontend game xp
Browse files- dashboards/student_db.py +28 -24
- phase/Student_view/game.py +30 -30
dashboards/student_db.py
CHANGED
|
@@ -14,6 +14,17 @@ def load_css(file_name: str):
|
|
| 14 |
except FileNotFoundError:
|
| 15 |
st.warning("⚠️ Stylesheet not found. Please ensure 'assets/styles.css' exists.")
|
| 16 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 17 |
def show_student_dashboard():
|
| 18 |
# Load CSS
|
| 19 |
css_path = os.path.join("assets", "styles.css")
|
|
@@ -139,36 +150,29 @@ def show_student_dashboard():
|
|
| 139 |
st.write("")
|
| 140 |
|
| 141 |
# --- XP Bar ---
|
| 142 |
-
|
| 143 |
-
|
| 144 |
-
|
| 145 |
-
|
| 146 |
-
# prefer server
|
| 147 |
-
into =
|
| 148 |
-
need =
|
| 149 |
-
|
| 150 |
-
|
| 151 |
-
|
| 152 |
-
|
| 153 |
-
|
| 154 |
-
|
| 155 |
-
|
| 156 |
-
need =
|
| 157 |
-
if into == need:
|
| 158 |
-
level += 1
|
| 159 |
-
into = 0
|
| 160 |
-
|
| 161 |
-
pct = 0 if need <= 0 else min(100, int(round((into / need) * 100)))
|
| 162 |
|
| 163 |
st.markdown(
|
| 164 |
f"""
|
| 165 |
<div class="xp-card">
|
| 166 |
<span class="xp-level">Level {level}</span>
|
| 167 |
<span class="xp-text">{into:,} / {need:,} XP</span>
|
| 168 |
-
<div class="xp-bar">
|
| 169 |
-
|
| 170 |
-
</div>
|
| 171 |
-
<div class="xp-total">Total XP: {xp:,}</div>
|
| 172 |
</div>
|
| 173 |
""",
|
| 174 |
unsafe_allow_html=True
|
|
|
|
| 14 |
except FileNotFoundError:
|
| 15 |
st.warning("⚠️ Stylesheet not found. Please ensure 'assets/styles.css' exists.")
|
| 16 |
|
| 17 |
+
def _level_progress(total_xp: int, base: int = 500):
|
| 18 |
+
xp = int(max(0, total_xp))
|
| 19 |
+
level = max(1, xp // base + 1)
|
| 20 |
+
into = xp - (level - 1) * base
|
| 21 |
+
need = base
|
| 22 |
+
if into == need: # exact boundary
|
| 23 |
+
level += 1
|
| 24 |
+
into = 0
|
| 25 |
+
pct = int(round(100 * into / need)) if need else 0
|
| 26 |
+
return level, into, need, pct
|
| 27 |
+
|
| 28 |
def show_student_dashboard():
|
| 29 |
# Load CSS
|
| 30 |
css_path = os.path.join("assets", "styles.css")
|
|
|
|
| 150 |
st.write("")
|
| 151 |
|
| 152 |
# --- XP Bar ---
|
| 153 |
+
# --- XP Bar (live, per-level) ---
|
| 154 |
+
total_xp = int(stats.get("xp", 0))
|
| 155 |
+
level_api = int(stats.get("level", 1))
|
| 156 |
+
|
| 157 |
+
# prefer server fields if present
|
| 158 |
+
into = stats.get("into")
|
| 159 |
+
need = stats.get("need")
|
| 160 |
+
|
| 161 |
+
if isinstance(into, (int, float)) and isinstance(need, (int, float)) and need > 0:
|
| 162 |
+
level = level_api
|
| 163 |
+
into = int(into)
|
| 164 |
+
need = int(need)
|
| 165 |
+
pct = min(100, int(round(100 * into / need)))
|
| 166 |
+
else:
|
| 167 |
+
level, into, need, pct = _level_progress(total_xp)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 168 |
|
| 169 |
st.markdown(
|
| 170 |
f"""
|
| 171 |
<div class="xp-card">
|
| 172 |
<span class="xp-level">Level {level}</span>
|
| 173 |
<span class="xp-text">{into:,} / {need:,} XP</span>
|
| 174 |
+
<div class="xp-bar"><div class="xp-fill" style="width:{pct}%;"></div></div>
|
| 175 |
+
<div class="xp-total">Total XP: {total_xp:,}</div>
|
|
|
|
|
|
|
| 176 |
</div>
|
| 177 |
""",
|
| 178 |
unsafe_allow_html=True
|
phase/Student_view/game.py
CHANGED
|
@@ -16,6 +16,16 @@ def load_css(file_name: str):
|
|
| 16 |
|
| 17 |
st.session_state.setdefault("current_game", None)
|
| 18 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 19 |
|
| 20 |
# --- GAME RENDERERS ---
|
| 21 |
def _render_budget_builder():
|
|
@@ -259,45 +269,36 @@ def show_games():
|
|
| 259 |
# pull live XP/level
|
| 260 |
user_id = st.session_state.user["user_id"]
|
| 261 |
|
| 262 |
-
#
|
| 263 |
-
|
| 264 |
-
|
| 265 |
-
|
| 266 |
-
|
| 267 |
-
stats = api.user_stats(user_id)
|
| 268 |
-
|
| 269 |
-
|
| 270 |
-
stats = {"xp": int(st.session_state.get("xp", 0)), "level": 1, "streak": 0}
|
| 271 |
|
| 272 |
total_xp = int(stats.get("xp", 0))
|
| 273 |
-
|
| 274 |
-
st.session_state.xp
|
| 275 |
st.session_state.streak = int(stats.get("streak", 0))
|
| 276 |
|
| 277 |
-
# Use server-provided per-level values when available
|
| 278 |
into = stats.get("into")
|
| 279 |
need = stats.get("need")
|
| 280 |
|
| 281 |
-
|
| 282 |
-
|
| 283 |
-
|
| 284 |
-
|
| 285 |
-
|
| 286 |
-
|
| 287 |
-
need =
|
| 288 |
-
|
| 289 |
-
|
| 290 |
-
into = 0
|
| 291 |
-
|
| 292 |
-
into = int(max(0, into))
|
| 293 |
-
need = int(max(1, need))
|
| 294 |
-
progress_pct = min(100, int(round((into / need) * 100)))
|
| 295 |
-
|
| 296 |
-
st.write(f"Level {level} Experience Points")
|
| 297 |
st.markdown(f"""
|
| 298 |
<div style="background:#e0e0e0;border-radius:12px;padding:3px;width:100%;">
|
| 299 |
<div style="
|
| 300 |
-
width:{
|
| 301 |
background:linear-gradient(135deg,#22c55e,#059669);
|
| 302 |
height:24px;border-radius:10px;text-align:right;
|
| 303 |
color:white;font-weight:bold;padding-right:8px;line-height:24px;">
|
|
@@ -309,7 +310,6 @@ def show_games():
|
|
| 309 |
|
| 310 |
|
| 311 |
|
| 312 |
-
|
| 313 |
st.markdown("---")
|
| 314 |
|
| 315 |
# Game list
|
|
|
|
| 16 |
|
| 17 |
st.session_state.setdefault("current_game", None)
|
| 18 |
|
| 19 |
+
def _level_progress(total_xp: int, base: int = 500):
|
| 20 |
+
xp = int(max(0, total_xp))
|
| 21 |
+
level = max(1, xp // base + 1)
|
| 22 |
+
into = xp - (level - 1) * base
|
| 23 |
+
need = base
|
| 24 |
+
if into == need:
|
| 25 |
+
level += 1
|
| 26 |
+
into = 0
|
| 27 |
+
pct = int(round(100 * into / need)) if need else 0
|
| 28 |
+
return level, into, need, pct
|
| 29 |
|
| 30 |
# --- GAME RENDERERS ---
|
| 31 |
def _render_budget_builder():
|
|
|
|
| 269 |
# pull live XP/level
|
| 270 |
user_id = st.session_state.user["user_id"]
|
| 271 |
|
| 272 |
+
# DB if enabled, else backend
|
| 273 |
+
try:
|
| 274 |
+
if USE_LOCAL_DB and hasattr(dbapi, "user_xp_and_level"):
|
| 275 |
+
stats = dbapi.user_xp_and_level(user_id)
|
| 276 |
+
else:
|
| 277 |
+
stats = api.user_stats(user_id) # /students/{id}/stats
|
| 278 |
+
except Exception:
|
| 279 |
+
stats = {"xp": int(st.session_state.get("xp", 0)), "level": 1, "streak": 0}
|
|
|
|
| 280 |
|
| 281 |
total_xp = int(stats.get("xp", 0))
|
| 282 |
+
level_api = int(stats.get("level", 1))
|
| 283 |
+
st.session_state.xp = total_xp
|
| 284 |
st.session_state.streak = int(stats.get("streak", 0))
|
| 285 |
|
|
|
|
| 286 |
into = stats.get("into")
|
| 287 |
need = stats.get("need")
|
| 288 |
|
| 289 |
+
if isinstance(into, (int, float)) and isinstance(need, (int, float)) and need > 0:
|
| 290 |
+
level = level_api
|
| 291 |
+
into = int(into)
|
| 292 |
+
need = int(need)
|
| 293 |
+
pct = min(100, int(round(100 * into / need)))
|
| 294 |
+
else:
|
| 295 |
+
level, into, need, pct = _level_progress(total_xp)
|
| 296 |
+
|
| 297 |
+
st.write(f"Level {level} Experience Points")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 298 |
st.markdown(f"""
|
| 299 |
<div style="background:#e0e0e0;border-radius:12px;padding:3px;width:100%;">
|
| 300 |
<div style="
|
| 301 |
+
width:{pct}%;
|
| 302 |
background:linear-gradient(135deg,#22c55e,#059669);
|
| 303 |
height:24px;border-radius:10px;text-align:right;
|
| 304 |
color:white;font-weight:bold;padding-right:8px;line-height:24px;">
|
|
|
|
| 310 |
|
| 311 |
|
| 312 |
|
|
|
|
| 313 |
st.markdown("---")
|
| 314 |
|
| 315 |
# Game list
|