generated from nhcarrigan/template
feat: add ~100 new achievements for extended gameplay
Add extensive new achievement system covering: - Extended token/code/file/message milestones - Tool mastery achievements (Edit, Write, Glob, Task, WebFetch, MCP) - Daily streaks (week, two-week, month, quarter) - Time-based achievements (morning, night, lunch, coffee break) - Day-specific achievements (Monday, Wednesday, Friday, weekend) - Special day achievements (New Year, Valentine's, Halloween, Christmas, Leap Day) - Message content achievements (long messages, markdown, code blocks) - Emotional achievements (frustrated, excited, confused, curious, impressed) - Programming language achievements (Rust, Python, JS, TS, Go, C++, Java, etc.) - Project type achievements (frontend, backend, config, docs) - Refactoring/testing/documentation achievements - Completion percentage achievements (50%, 75%, 100%) Also adds streak tracking infrastructure to stats: - Session counting - Consecutive day tracking - Morning/night session tracking - Total days used tracking
This commit is contained in:
+1485
-2
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,5 @@
|
|||||||
use crate::achievements::{check_achievements, AchievementProgress};
|
use crate::achievements::{check_achievements, AchievementProgress};
|
||||||
|
use chrono::{Local, Timelike};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
@@ -28,6 +29,14 @@ pub struct UsageStats {
|
|||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
pub session_start: Option<Instant>,
|
pub session_start: Option<Instant>,
|
||||||
|
|
||||||
|
// Extended tracking for achievements
|
||||||
|
pub sessions_started: u64,
|
||||||
|
pub consecutive_days: u64,
|
||||||
|
pub total_days_used: u64,
|
||||||
|
pub morning_sessions: u64, // Sessions started before 9 AM
|
||||||
|
pub night_sessions: u64, // Sessions started after 10 PM
|
||||||
|
pub last_session_date: Option<String>, // ISO date string for streak tracking
|
||||||
|
|
||||||
// Achievement tracking
|
// Achievement tracking
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
pub achievements: AchievementProgress,
|
pub achievements: AchievementProgress,
|
||||||
@@ -65,6 +74,47 @@ impl UsageStats {
|
|||||||
self.session_duration_seconds = 0;
|
self.session_duration_seconds = 0;
|
||||||
self.session_start = Some(Instant::now());
|
self.session_start = Some(Instant::now());
|
||||||
self.achievements.start_session();
|
self.achievements.start_session();
|
||||||
|
|
||||||
|
// Track session start for achievements
|
||||||
|
self.track_session_start();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn track_session_start(&mut self) {
|
||||||
|
let now = Local::now();
|
||||||
|
let today = now.format("%Y-%m-%d").to_string();
|
||||||
|
let hour = now.hour();
|
||||||
|
|
||||||
|
// Increment session count
|
||||||
|
self.sessions_started += 1;
|
||||||
|
|
||||||
|
// Track morning/night sessions
|
||||||
|
if hour < 9 {
|
||||||
|
self.morning_sessions += 1;
|
||||||
|
}
|
||||||
|
if hour >= 22 {
|
||||||
|
self.night_sessions += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Track consecutive days and total days
|
||||||
|
if let Some(last_date) = &self.last_session_date {
|
||||||
|
if last_date != &today {
|
||||||
|
// Check if it's the next day (consecutive)
|
||||||
|
if is_consecutive_day(last_date, &today) {
|
||||||
|
self.consecutive_days += 1;
|
||||||
|
} else {
|
||||||
|
// Streak broken
|
||||||
|
self.consecutive_days = 1;
|
||||||
|
}
|
||||||
|
self.total_days_used += 1;
|
||||||
|
self.last_session_date = Some(today);
|
||||||
|
}
|
||||||
|
// Same day - don't increment anything
|
||||||
|
} else {
|
||||||
|
// First session ever
|
||||||
|
self.consecutive_days = 1;
|
||||||
|
self.total_days_used = 1;
|
||||||
|
self.last_session_date = Some(today);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn increment_messages(&mut self) {
|
pub fn increment_messages(&mut self) {
|
||||||
@@ -127,12 +177,34 @@ impl UsageStats {
|
|||||||
session_tools_usage: self.session_tools_usage.clone(),
|
session_tools_usage: self.session_tools_usage.clone(),
|
||||||
session_duration_seconds: self.session_duration_seconds,
|
session_duration_seconds: self.session_duration_seconds,
|
||||||
session_start: self.session_start,
|
session_start: self.session_start,
|
||||||
|
sessions_started: self.sessions_started,
|
||||||
|
consecutive_days: self.consecutive_days,
|
||||||
|
total_days_used: self.total_days_used,
|
||||||
|
morning_sessions: self.morning_sessions,
|
||||||
|
night_sessions: self.night_sessions,
|
||||||
|
last_session_date: self.last_session_date.clone(),
|
||||||
achievements: AchievementProgress::new(), // Dummy for copy
|
achievements: AchievementProgress::new(), // Dummy for copy
|
||||||
};
|
};
|
||||||
check_achievements(&stats_copy, &mut self.achievements)
|
check_achievements(&stats_copy, &mut self.achievements)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Helper function to check if two dates are consecutive
|
||||||
|
fn is_consecutive_day(prev_date: &str, current_date: &str) -> bool {
|
||||||
|
use chrono::NaiveDate;
|
||||||
|
|
||||||
|
let prev = NaiveDate::parse_from_str(prev_date, "%Y-%m-%d").ok();
|
||||||
|
let current = NaiveDate::parse_from_str(current_date, "%Y-%m-%d").ok();
|
||||||
|
|
||||||
|
match (prev, current) {
|
||||||
|
(Some(p), Some(c)) => {
|
||||||
|
let diff = c.signed_duration_since(p).num_days();
|
||||||
|
diff == 1
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Pricing as of January 2025
|
// Pricing as of January 2025
|
||||||
// https://www.anthropic.com/pricing
|
// https://www.anthropic.com/pricing
|
||||||
fn calculate_cost(input_tokens: u64, output_tokens: u64, model: &str) -> f64 {
|
fn calculate_cost(input_tokens: u64, output_tokens: u64, model: &str) -> f64 {
|
||||||
|
|||||||
Reference in New Issue
Block a user