text=f"🪙 {self.
current_user['coins']}",
font=("Arial", 12),
text_color=("#FFD700", "#FFA500")
)
coins_label.pack(side="left", padx=5, pady=10)
# Gems
gems_label = ctk.CTkLabel(
self.user_info_frame,
text=f"💎 {self.current_user['gems']}",
font=("Arial", 12),
text_color=("#00FFFF", "#87CEEB")
)
gems_label.pack(side="left", padx=5, pady=10)
# Streak
streak_label = ctk.CTkLabel(
self.user_info_frame,
text=f"🔥 {self.current_user['current_streak']}",
font=("Arial", 12),
text_color=("#FF6B35", "#FF8C42")
)
streak_label.pack(side="left", padx=5, pady=10)
else:
# Guest or not logged in
guest_label = ctk.CTkLabel(
self.user_info_frame,
text="👤 Guest Mode",
font=("Arial", 14)
)
guest_label.pack(padx=10, pady=10)
def create_footer(self):
"""Create application footer"""
# Version info
version_label = ctk.CTkLabel(
self.footer_frame,
text="Quarix v2.0 | Powered by Gemini AI",
font=("Arial", 10),
text_color=("#666666", "#AAAAAA")
)
version_label.pack(side="left", padx=20, pady=15)
# Status indicator
self.status_label = ctk.CTkLabel(
self.footer_frame,
text="🟢 Ready",
font=("Arial", 10),
text_color=("#00FF00", "#90EE90")
)
self.status_label.pack(side="right", padx=20, pady=15)
def update_status(self, message, color=("#00FF00", "#90EE90")):
"""Update status message"""
self.status_label.configure(text=message, text_color=color)
self.root.update()
def clear_content(self):
"""Clear content frame"""
for widget in self.content_frame.winfo_children():
widget.destroy()
def show_splash_screen(self):
"""Show animated splash screen"""
self.clear_content()
# Splash container
splash_frame = ctk.CTkFrame(self.content_frame)
splash_frame.pack(expand=True, fill="both")
# Logo
logo_label = ctk.CTkLabel(
splash_frame,
text="🧠",
font=("Arial", 120)
)
logo_label.pack(pady=(150, 20))
# Title
title_label = ctk.CTkLabel(
splash_frame,
text="QUARIX",
font=("Arial", 48, "bold"),
text_color=("#00d4ff", "#ffffff")
)
title_label.pack(pady=10)
# Subtitle
subtitle_label = ctk.CTkLabel(
splash_frame,
text="AI-Powered Quiz Platform",
font=("Arial", 18),
text_color=("#888888", "#CCCCCC")
)
subtitle_label.pack(pady=5)
# Loading animation
self.loading_label = ctk.CTkLabel(
splash_frame,
text="Loading...",
font=("Arial", 14)
)
self.loading_label.pack(pady=30)
# Progress bar
self.progress_bar = ctk.CTkProgressBar(splash_frame,
width=300)
self.progress_bar.pack(pady=20)
self.progress_bar.set(0)
# Start loading animation
self.animate_loading()
def animate_loading(self):
"""Animate loading screen"""
loading_texts = ["Loading...", "Initializing AI...",
"Preparing Questions...", "Almost Ready..."]
def update_progress(step):
if step < len(loading_texts):
self.loading_label.configure(text=loading_texts[step])
self.progress_bar.set((step + 1) / len(loading_texts))
self.root.after(800, lambda: update_progress(step +
1))
else:
self.root.after(500, self.show_home_screen)
update_progress(0)
def show_home_screen(self):
"""Show main home screen"""
self.clear_content()
self.update_status("🏠 Home")
# Welcome section
welcome_frame = ctk.CTkFrame(self.content_frame)
welcome_frame.pack(fill="x", padx=20, pady=20)
welcome_text = f"Welcome back,
{self.current_user['username']}!" if self.current_user else "Welcome
to Quarix!"
welcome_label = ctk.CTkLabel(
welcome_frame,
text=f"👋 {welcome_text}",
font=("Arial", 24, "bold")
)
welcome_label.pack(pady=20)
# Quick stats (if user logged in)
if self.current_user:
stats =
self.db_manager.get_user_statistics(self.current_user['id'])
stats_frame = ctk.CTkFrame(welcome_frame)
stats_frame.pack(fill="x", padx=20, pady=10)
quick_stats = [
("📊 Quizzes Completed", str(stats['total_quizzes'])),
("🎯 Average Score", f"{stats['average_score']:.1f}%"),
("🔥 Current Streak", f"{stats['current_streak']}
days")
]
for i, (label, value) in enumerate(quick_stats):
stat_frame = ctk.CTkFrame(stats_frame)
stat_frame.pack(side="left", fill="both", expand=True,
padx=5, pady=10)
ctk.CTkLabel(stat_frame, text=label, font=("Arial",
12)).pack(pady=5)
ctk.CTkLabel(stat_frame, text=value, font=("Arial",
16, "bold"),
text_color=("#00d4ff",
"#ffffff")).pack(pady=5)
# Main action buttons
actions_frame = ctk.CTkFrame(self.content_frame)
actions_frame.pack(fill="both", expand=True, padx=20, pady=20)
# Create grid of action buttons
buttons_data = [
("🎯 Start Quiz", "Begin a new quiz session",
self.show_quiz_setup, "#4CAF50"),
("📚 Study Mode", "Browse topics and study materials",
self.show_study_mode, "#2196F3"),
("🏆 Leaderboard", "View global rankings",
self.show_leaderboard_screen, "#FF9800"),
("🛒 Shop", "Buy power-ups and items",
self.show_shop_screen, "#9C27B0"),
("👤 Profile", "View your profile and stats",
self.show_profile_screen, "#607D8B"),
("🤖 AI Chat", "Chat with Quarix AI assistant",
self.show_ai_chat, "#00BCD4")
]
# Create 2x3 grid
for i, (title, desc, command, color) in
enumerate(buttons_data):
row = i // 3
col = i % 3
button_frame = ctk.CTkFrame(actions_frame)
button_frame.grid(row=row, column=col, padx=15, pady=15,
sticky="nsew")
# Configure grid weights
actions_frame.grid_rowconfigure(row, weight=1)
actions_frame.grid_columnconfigure(col, weight=1)
# Button
action_btn = ctk.CTkButton(
button_frame,
text=title,
command=command,
width=200,
height=80,
font=("Arial", 16, "bold"),
fg_color=color
)
action_btn.pack(pady=20, padx=20)
# Description
desc_label = ctk.CTkLabel(
button_frame,
text=desc,
font=("Arial", 12),
text_color=("#666666", "#AAAAAA"),
wraplength=180
)
desc_label.pack(pady=(0, 20))
# Quick access buttons at bottom
quick_frame = ctk.CTkFrame(self.content_frame)
quick_frame.pack(fill="x", padx=20, pady=10)
if not self.current_user:
login_btn = ctk.CTkButton(
quick_frame,
text="🔐 Login / Register",
command=self.show_auth_screen,
width=150,
height=35,
font=("Arial", 14)
)
login_btn.pack(side="right", padx=10, pady=10)
else:
logout_btn = ctk.CTkButton(
quick_frame,
text="🚪 Logout",
command=self.logout,
width=100,
height=35,
font=("Arial", 12),
fg_color=("#F44336", "#D32F2F")
)
logout_btn.pack(side="right", padx=10, pady=10)
def show_quiz_setup(self):
"""Show quiz setup screen"""
self.clear_content()
self.update_status("⚙️Quiz Setup")
# Title
title_label = ctk.CTkLabel(
self.content_frame,
text="🎯 Quiz Setup",
font=("Arial", 28, "bold")
)
title_label.pack(pady=30)
# Setup form
setup_frame = ctk.CTkFrame(self.content_frame)
setup_frame.pack(expand=True, padx=50, pady=20)
# Education Level
level_label = ctk.CTkLabel(setup_frame, text="🎓 Education
Level:", font=("Arial", 16, "bold"))
level_label.pack(pady=(30, 10))
self.level_var = ctk.StringVar(value="Primary")
level_menu = ctk.CTkOptionMenu(
setup_frame,
variable=self.level_var,
values=["Nursery", "Primary", "Secondary", "University"],
width=300,
height=40,
font=("Arial", 14),
command=self.update_class_options
)
level_menu.pack(pady=10)
# Class
class_label = ctk.CTkLabel(setup_frame, text="📚 Class:",
font=("Arial", 16, "bold"))
class_label.pack(pady=(20, 10))
self.class_var = ctk.StringVar(value="Primary 1")
self.class_menu = ctk.CTkOptionMenu(
setup_frame,
variable=self.class_var,
values=["Primary 1", "Primary 2", "Primary 3", "Primary
4", "Primary 5", "Primary 6"],
width=300,
height=40,
font=("Arial", 14),
command=self.update_subject_options
)
self.class_menu.pack(pady=10)
# Subject
subject_label = ctk.CTkLabel(setup_frame, text="📖 Subject:",
font=("Arial", 16, "bold"))
subject_label.pack(pady=(20, 10))
self.subject_var = ctk.StringVar(value="Mathematics")
self.subject_menu = ctk.CTkOptionMenu(
setup_frame,
variable=self.subject_var,
values=["Mathematics", "English", "Science", "Social
Studies"],
width=300,
height=40,
font=("Arial", 14),
command=self.update_topic_options
)
self.subject_menu.pack(pady=10)
# Topic
topic_label = ctk.CTkLabel(setup_frame, text="📝 Topic:",
font=("Arial", 16, "bold"))
topic_label.pack(pady=(20, 10))
self.topic_var = ctk.StringVar(value="Basic Addition")
self.topic_menu = ctk.CTkOptionMenu(
setup_frame,
variable=self.topic_var,
values=["Basic Addition", "Subtraction", "Multiplication",
"Division"],
width=300,
height=40,
font=("Arial", 14)
)
self.topic_menu.pack(pady=10)
# Number of questions
questions_label = ctk.CTkLabel(setup_frame, text="❓ Number of
Questions:", font=("Arial", 16, "bold"))
questions_label.pack(pady=(20, 10))
self.questions_var = ctk.StringVar(value="10")
questions_menu = ctk.CTkOptionMenu(
setup_frame,
variable=self.questions_var,
values=["5", "10", "15", "20", "25"],
width=300,
height=40,
font=("Arial", 14)
)
questions_menu.pack(pady=10)
# Difficulty
difficulty_label = ctk.CTkLabel(setup_frame, text="⚡
Difficulty:", font=("Arial", 16, "bold"))
difficulty_label.pack(pady=(20, 10))
self.difficulty_var = ctk.StringVar(value="Medium")
difficulty_menu = ctk.CTkOptionMenu(
setup_frame,
variable=self.difficulty_var,
values=["Easy", "Medium", "Hard"],
width=300,
height=40,
font=("Arial", 14)
)
difficulty_menu.pack(pady=10)
# Buttons
buttons_frame = ctk.CTkFrame(setup_frame)
buttons_frame.pack(pady=30)
start_btn = ctk.CTkButton(
buttons_frame,
text="🚀 Start Quiz",
command=self.start_quiz,
width=200,
height=50,
font=("Arial", 18, "bold"),
fg_color=("#4CAF50", "#45a049")
)
start_btn.pack(side="left", padx=20)
back_btn = ctk.CTkButton(
buttons_frame,
text="← Back",
command=self.show_home_screen,
width=100,
height=50,
font=("Arial", 16),
fg_color=("#666666", "#555555")
)
back_btn.pack(side="left", padx=20)
def update_class_options(self, level):
"""Update class options based on education level"""
class_options = {
"Nursery": ["Nursery 1", "Nursery 2"],
"Primary": ["Primary 1", "Primary 2", "Primary 3",
"Primary 4", "Primary 5", "Primary 6"],
"Secondary": ["JSS 1", "JSS 2", "JSS 3", "SS 1", "SS 2",
"SS 3"],
"University": ["100 Level", "200 Level", "300 Level", "400
Level", "500 Level", "600 Level"]
}
options = class_options.get(level, ["Primary 1"])
self.class_menu.configure(values=options)
self.class_var.set(options[0])
self.update_subject_options(options[0])
def update_subject_options(self, class_level):
"""Update subject options based on class level"""
if "Nursery" in class_level or "Primary 1" in class_level or
"Primary 2" in class_level:
subjects = ["Mathematics", "English", "Basic Science",
"Social Studies"]
elif "Primary" in class_level:
subjects = ["Mathematics", "English", "Basic Science",
"Social Studies", "Civic Education"]
elif "JSS" in class_level:
subjects = ["Mathematics", "English", "Basic Science",
"Social Studies", "Civic Education",
"Computer Studies", "French", "Creative Arts"]
elif "SS" in class_level:
subjects = ["Mathematics", "English", "Physics",
"Chemistry", "Biology", "Geography",
"Economics", "Government", "Literature",
"Computer Science"]
else: # University
subjects = ["Mathematics", "Physics", "Chemistry",
"Biology", "Computer Science",
"Engineering", "Medicine", "Law", "Business
Administration"]
self.subject_menu.configure(values=subjects)
self.subject_var.set(subjects[0])
self.update_topic_options(subjects[0])
def update_topic_options(self, subject):
"""Update topic options based on subject"""
topics_map = {
"Mathematics": ["Algebra", "Geometry", "Arithmetic",
"Statistics", "Calculus", "Trigonometry"],
"English": ["Grammar", "Comprehension", "Literature",
"Writing", "Vocabulary", "Phonics"],
"Physics": ["Motion", "Forces", "Energy", "Waves",
"Electricity", "Magnetism"],
"Chemistry": ["Atoms", "Molecules", "Reactions", "Acids
and Bases", "Organic Chemistry"],
"Biology": ["Human Body", "Plants", "Animals", "Genetics",
"Evolution", "Ecology"],
"Basic Science": ["Living Things", "Non-living Things",
"Weather", "Simple Machines"],
"Social Studies": ["Community", "Culture", "Geography",
"History", "Citizenship"],
"Computer Science": ["Programming", "Algorithms", "Data
Structures", "Networks", "Databases"]
}
topics = topics_map.get(subject, ["General Topics"])
self.topic_menu.configure(values=topics)
self.topic_var.set(topics[0])
def start_quiz(self):
"""Start the quiz with selected parameters"""
self.update_status("🔄 Generating Questions...", ("#FFA500",
"#FFB84D"))
# Get quiz parameters
class_level = self.class_var.get()
subject = self.subject_var.get()
topic = self.topic_var.get()
num_questions = int(self.questions_var.get())
difficulty = self.difficulty_var.get().lower()
# Generate questions in a separate thread to avoid UI freezing
def generate_and_start():
try:
questions =
self.question_generator.generate_questions(
class_level, subject, topic, num_questions,
difficulty
)
if questions:
self.current_questions = questions
self.current_question_index = 0
self.user_answers = []
self.quiz_start_time = time.time()
# Switch to quiz screen on main thread
self.root.after(0, self.show_quiz_screen)
else:
self.root.after(0, lambda: messagebox.showerror(
"Error", "Failed to generate questions. Please
try again."
))
self.root.after(0, self.show_home_screen)
except Exception as e:
self.root.after(0, lambda: messagebox.showerror(
"Error", f"Quiz generation failed: {str(e)}"
))
self.root.after(0, self.show_home_screen)
# Start generation in background
threading.Thread(target=generate_and_start,
daemon=True).start()
def show_quiz_screen(self):
"""Show the quiz interface"""
self.clear_content()
self.update_status("🎯 Quiz in Progress")
if not self.current_questions or self.current_question_index
>= len(self.current_questions):
self.show_quiz_results()
return
current_q =
self.current_questions[self.current_question_index]
# Quiz header
header_frame = ctk.CTkFrame(self.content_frame)
header_frame.pack(fill="x", padx=20, pady=20)
# Progress info
progress_text = f"Question {self.current_question_index + 1}
of {len(self.current_questions)}"
progress_label = ctk.CTkLabel(
header_frame,
text=progress_text,
font=("Arial", 16, "bold")
)
progress_label.pack(side="left", padx=20, pady=15)
# Progress bar
progress_bar = ctk.CTkProgressBar(header_frame, width=300)
progress_bar.pack(side="right", padx=20, pady=15)
progress_bar.set((self.current_question_index + 1) /
len(self.current_questions))
# Question frame
question_frame = ctk.CTkFrame(self.content_frame)
question_frame.pack(fill="both", expand=True, padx=20,
pady=20)
# Question text
question_label = ctk.CTkLabel(
question_frame,
text=current_q["question"],
font=("Arial", 20, "bold"),
wraplength=800,
justify="center"
)
question_label.pack(pady=40)
# Options frame
options_frame = ctk.CTkFrame(question_frame)
options_frame.pack(expand=True, padx=40, pady=20)
# Reset selection
self.selected_option.set("")
# Create option buttons
self.option_buttons = []
for i, option in enumerate(current_q["options"]):
btn = ctk.CTkRadioButton(
options_frame,
text=f"{chr(65+i)}. {option}",
variable=self.selected_option,
value=str(i),
font=("Arial", 16),
radiobutton_width=20,
radiobutton_height=20
)
btn.pack(anchor="w", padx=40, pady=15)
self.option_buttons.append(btn)
# Navigation buttons
nav_frame = ctk.CTkFrame(self.content_frame)
nav_frame.pack(fill="x", padx=20, pady=20)
# Previous button (if not first question)
if self.current_question_index > 0:
prev_btn = ctk.CTkButton(
nav_frame,
text="← Previous",
command=self.previous_question,
width=120,
height=40,
font=("Arial", 14),
fg_color=("#666666", "#555555")
)
prev_btn.pack(side="left", padx=20, pady=10)
# Next/Submit button
if self.current_question_index < len(self.current_questions) -
1:
next_btn = ctk.CTkButton(
nav_frame,
text="Next →",
command=self.next_question,
width=120,
height=40,
font=("Arial", 14, "bold"),
fg_color=("#4CAF50", "#45a049")
)
next_btn.pack(side="right", padx=20, pady=10)
else:
submit_btn = ctk.CTkButton(
nav_frame,
text="🏁 Submit Quiz",
command=self.submit_quiz,
width=150,
height=40,
font=("Arial", 14, "bold"),
fg_color=("#FF5722", "#E64A19")
)
submit_btn.pack(side="right", padx=20, pady=10)
# Quit button
quit_btn = ctk.CTkButton(
nav_frame,
text="❌ Quit Quiz",
command=self.quit_quiz,
width=120,
height=40,
font=("Arial", 12),
fg_color=("#F44336", "#D32F2F")
)
quit_btn.pack(side="left" if self.current_question_index == 0
else "right", padx=20, pady=10)
def next_question(self):
"""Move to next question"""
# Save current answer
selected = self.selected_option.get()
if selected:
self.user_answers.append(int(selected))
else:
self.user_answers.append(-1) # No answer selected
self.current_question_index += 1
self.show_quiz_screen()
def previous_question(self):
"""Move to previous question"""
if self.current_question_index > 0:
# Remove last answer if going back
if len(self.user_answers) > self.current_question_index:
self.user_answers.pop()
self.current_question_index -= 1
# Restore previous answer if exists
if self.current_question_index < len(self.user_answers):
prev_answer =
self.user_answers[self.current_question_index]
if prev_answer >= 0:
self.selected_option.set(str(prev_answer))
self.show_quiz_screen()
def submit_quiz(self):
"""Submit the quiz and show results"""
# Save final answer
selected = self.selected_option.get()
if selected:
self.user_answers.append(int(selected))
else:
self.user_answers.append(-1)
# Confirm submission
if messagebox.askyesno("Submit Quiz", "Are you sure you want
to submit your quiz?"):
self.show_quiz_results()
def quit_quiz(self):
"""Quit the current quiz"""
if messagebox.askyesno("Quit Quiz", "Are you sure you want to
quit? Your progress will be lost."):
self.show_home_screen()
def show_quiz_results(self):
"""Show quiz results and statistics"""
self.clear_content()
self.update_status("📊 Quiz Complete")
# Calculate results
correct_answers = 0
total_questions = len(self.current_questions)
quiz_time = int(time.time() - self.quiz_start_time) if
self.quiz_start_time else 0
for i, user_answer in enumerate(self.user_answers):
if i < len(self.current_questions) and user_answer ==
self.current_questions[i]["correct"]:
correct_answers += 1
percentage = (correct_answers / total_questions * 100) if
total_questions > 0 else 0
# Play completion sound
self.play_sound("celebration.wav")
# Results header
results_frame = ctk.CTkFrame(self.content_frame)
results_frame.pack(fill="x", padx=20, pady=20)
# Celebration message based on score
if percentage >= 90:
celebration = "🎉 Outstanding! 🎉"
message = "Excellent work! You're a quiz master!"
color = ("#4CAF50", "#66BB6A")
elif percentage >= 80:
celebration = "🌟 Great Job! 🌟"
message = "Well done! Keep up the good work!"
color = ("#2196F3", "#42A5F5")
elif percentage >= 70:
celebration = "👍 Good Work! 👍"
message = "Nice effort! You're improving!"
color = ("#FF9800", "#FFA726")
elif percentage >= 60:
celebration = "📚 Keep Learning! 📚"
message = "Good try! Practice makes perfect!"
color = ("#FF5722", "#FF7043")
else:
celebration = "💪 Don't Give Up! 💪"
message = "Keep practicing! You'll get better!"
color = ("#9C27B0", "#BA68C8")
celebration_label = ctk.CTkLabel(
results_frame,
text=celebration,
font=("Arial", 28, "bold"),
text_color=color
)
celebration_label.pack(pady=20)
message_label = ctk.CTkLabel(
results_frame,
text=message,
font=("Arial", 16),
text_color=("#666666", "#AAAAAA")
)
message_label.pack(pady=10)
# Score display
score_frame = ctk.CTkFrame(self.content_frame)
score_frame.pack(fill="x", padx=20, pady=20)
# Main score
score_label = ctk.CTkLabel(
score_frame,
text=f"{percentage:.1f}%",
font=("Arial", 72, "bold"),
text_color=color
)
score_label.pack(pady=30)
# Detailed stats
stats_frame = ctk.CTkFrame(score_frame)
stats_frame.pack(fill="x", padx=40, pady=20)
stats_data = [
("✅ Correct Answers",
f"{correct_answers}/{total_questions}"),
(" Time Taken", f"{quiz_time // 60}m {quiz_time % 60}s"),
("📊 Accuracy", f"{percentage:.1f}%"),
("🎯 Questions per Minute", f"{total_questions /
max(quiz_time / 60, 1):.1f}")
]
for i, (label, value) in enumerate(stats_data):
stat_frame = ctk.CTkFrame(stats_frame)
stat_frame.pack(side="left", fill="both", expand=True,
padx=5, pady=10)
ctk.CTkLabel(stat_frame, text=label, font=("Arial",
12)).pack(pady=5)
ctk.CTkLabel(stat_frame, text=value, font=("Arial", 16,
"bold"),
text_color=("#00d4ff",
"#ffffff")).pack(pady=5)
# Rewards section
if self.current_user:
rewards_frame = ctk.CTkFrame(self.content_frame)
rewards_frame.pack(fill="x", padx=20, pady=20)
# Calculate rewards
base_coins = int(percentage / 10) * 5 # 5 coins per 10%
score
time_bonus = max(0, 60 - quiz_time) if quiz_time < 60 else
0 # Bonus for speed
total_coins = base_coins + time_bonus
gems_earned = 1