From 1dd68b1cf24eb83e50d5a2ed7b21dc5a14ff19d1 Mon Sep 17 00:00:00 2001 From: devikrishna111 Date: Thu, 12 Mar 2026 21:42:15 +0530 Subject: [PATCH 1/3] Done adding the sound effect. --- Typing-Test | 1 + typing_speed_test.py | 32 +++++++++++++++++++++++++++++++- 2 files changed, 32 insertions(+), 1 deletion(-) create mode 160000 Typing-Test diff --git a/Typing-Test b/Typing-Test new file mode 160000 index 0000000..8463ec6 --- /dev/null +++ b/Typing-Test @@ -0,0 +1 @@ +Subproject commit 8463ec60d837ef175dcdeaa12a7c084c7d776e4a diff --git a/typing_speed_test.py b/typing_speed_test.py index bccbae5..d7533cd 100644 --- a/typing_speed_test.py +++ b/typing_speed_test.py @@ -1,6 +1,7 @@ import customtkinter as ctk import random import time +import winsound ctk.set_appearance_mode("light") ctk.set_default_color_theme("blue") @@ -47,7 +48,7 @@ def __init__(self): ) self.timer_label.pack() - # SENTENCE FRAME (for better visibility) + # SENTENCE FRAME self.sentence_frame = ctk.CTkFrame(self, width=620, height=100) self.sentence_frame.pack(pady=20) self.sentence_frame.pack_propagate(False) @@ -72,6 +73,9 @@ def __init__(self): self.input_textbox.pack(pady=10) self.input_textbox.configure(state="disabled") + # bind key press for sound + self.input_textbox.bind("", self.play_typing_sound) + # RESULT self.result_label = ctk.CTkLabel( self, @@ -210,6 +214,30 @@ def toggle_pause(self): self.pause_button.configure(text="Pause") self.update_timer() + # ====================== + # PLAY TYPING SOUND + # ====================== + def play_typing_sound(self, event): + + if not self.timer_running: + return + + typed = self.input_textbox.get("1.0", "end-1c") + index = len(typed) + + if event.keysym == "BackSpace": + winsound.Beep(500, 40) + return + + if index < len(self.current_sentence): + + expected_char = self.current_sentence[index] + + if event.char == expected_char: + winsound.Beep(800, 30) # correct key + else: + winsound.Beep(300, 80) # wrong key + # ====================== # RESULT # ====================== @@ -220,6 +248,8 @@ def check_result(self): self.timer_running = False + winsound.Beep(1200, 300) # completion sound + typed_text = self.input_textbox.get("1.0", "end-1c") elapsed_time = time.time() - self.start_time From b292200ac6133c2c5f4826f09011b05106716e3f Mon Sep 17 00:00:00 2001 From: devikrishna111 Date: Thu, 12 Mar 2026 21:55:46 +0530 Subject: [PATCH 2/3] Added Streak System --- streak_data.json | 1 + typing_speed_test.py | 145 +++++++++++++++++++++++++++++++++---------- 2 files changed, 114 insertions(+), 32 deletions(-) create mode 100644 streak_data.json diff --git a/streak_data.json b/streak_data.json new file mode 100644 index 0000000..54990c5 --- /dev/null +++ b/streak_data.json @@ -0,0 +1 @@ +{"daily_streak": 1, "last_practice_date": "2026-03-12", "improvement_streak": 2, "personal_best_streak": 2, "best_wpm": 25.100241252979508, "last_wpm": 25.100241252979508} \ No newline at end of file diff --git a/typing_speed_test.py b/typing_speed_test.py index d7533cd..81c95a0 100644 --- a/typing_speed_test.py +++ b/typing_speed_test.py @@ -2,11 +2,15 @@ import random import time import winsound +import json +import os +from datetime import datetime, timedelta ctk.set_appearance_mode("light") ctk.set_default_color_theme("blue") TEST_DURATION = 60 +DATA_FILE = "streak_data.json" SENTENCES = [ "Technology is the most effective way to change the world.", @@ -17,13 +21,37 @@ ] +# ====================== +# LOAD / SAVE DATA +# ====================== + +def load_data(): + if os.path.exists(DATA_FILE): + with open(DATA_FILE, "r") as f: + return json.load(f) + + return { + "daily_streak": 0, + "last_practice_date": "", + "improvement_streak": 0, + "personal_best_streak": 0, + "best_wpm": 0, + "last_wpm": 0 + } + + +def save_data(data): + with open(DATA_FILE, "w") as f: + json.dump(data, f) + + class TypingSpeedTest(ctk.CTk): def __init__(self): super().__init__() self.title("Typing Speed Test") - self.geometry("700x520") + self.geometry("720x580") self.current_sentence = "" self.start_time = None @@ -32,13 +60,15 @@ def __init__(self): self.paused = False self.countdown = 3 + self.data = load_data() + # TITLE self.title_label = ctk.CTkLabel( self, text="Typing Speed Test", font=("Helvetica", 30, "bold") ) - self.title_label.pack(pady=20) + self.title_label.pack(pady=15) # TIMER self.timer_label = ctk.CTkLabel( @@ -53,7 +83,6 @@ def __init__(self): self.sentence_frame.pack(pady=20) self.sentence_frame.pack_propagate(False) - # SENTENCE LABEL self.sentence_label = ctk.CTkLabel( self.sentence_frame, text="Press Start to begin", @@ -73,22 +102,28 @@ def __init__(self): self.input_textbox.pack(pady=10) self.input_textbox.configure(state="disabled") - # bind key press for sound - self.input_textbox.bind("", self.play_typing_sound) + self.input_textbox.bind("", self.handle_typing) - # RESULT + # RESULT LABEL self.result_label = ctk.CTkLabel( self, text="", - font=("Helvetica", 20, "bold") + font=("Helvetica", 18, "bold") ) self.result_label.pack(pady=10) + # STREAK LABEL + self.streak_label = ctk.CTkLabel( + self, + text=self.get_streak_text(), + font=("Helvetica", 16) + ) + self.streak_label.pack(pady=5) + # BUTTON FRAME self.button_frame = ctk.CTkFrame(self) self.button_frame.pack(pady=10) - # START BUTTON self.start_button = ctk.CTkButton( self.button_frame, text="Start Test", @@ -96,7 +131,6 @@ def __init__(self): ) self.start_button.grid(row=0, column=0, padx=10) - # PAUSE BUTTON self.pause_button = ctk.CTkButton( self.button_frame, text="Pause", @@ -105,24 +139,27 @@ def __init__(self): ) self.pause_button.grid(row=0, column=1, padx=10) - # RESULT BUTTON - self.result_button = ctk.CTkButton( - self.button_frame, - text="Check Result", - command=self.check_result, - state="disabled" + # ====================== + # STREAK TEXT + # ====================== + + def get_streak_text(self): + return ( + f"🔥 Daily Streak: {self.data['daily_streak']} days\n" + f"📈 Improvement Streak: {self.data['improvement_streak']}\n" + f"🏆 Personal Best Streak: {self.data['personal_best_streak']}\n" + f"⭐ Best WPM: {self.data['best_wpm']}" ) - self.result_button.grid(row=0, column=2, padx=10) # ====================== # START TEST # ====================== + def start_test(self): self.result_label.configure(text="") self.countdown = 3 self.input_textbox.configure(state="disabled") - self.start_button.configure(state="disabled") self.show_countdown() @@ -130,6 +167,7 @@ def start_test(self): # ====================== # COUNTDOWN # ====================== + def show_countdown(self): if self.countdown > 0: @@ -145,12 +183,12 @@ def show_countdown(self): else: self.sentence_label.configure(text="GO!") - self.after(800, self.begin_test) # ====================== # BEGIN TEST # ====================== + def begin_test(self): self.current_sentence = random.choice(SENTENCES) @@ -167,13 +205,13 @@ def begin_test(self): self.paused = False self.pause_button.configure(state="normal") - self.result_button.configure(state="normal") self.update_timer() # ====================== # TIMER # ====================== + def update_timer(self): if not self.timer_running: @@ -188,36 +226,34 @@ def update_timer(self): ) self.time_left -= 1 - self.after(1000, self.update_timer) else: - self.check_result() # ====================== - # PAUSE / RESUME + # PAUSE # ====================== + def toggle_pause(self): if not self.timer_running: return if not self.paused: - self.paused = True self.pause_button.configure(text="Resume") else: - self.paused = False self.pause_button.configure(text="Pause") self.update_timer() # ====================== - # PLAY TYPING SOUND + # HANDLE TYPING + SOUND # ====================== - def play_typing_sound(self, event): + + def handle_typing(self, event): if not self.timer_running: return @@ -229,18 +265,57 @@ def play_typing_sound(self, event): winsound.Beep(500, 40) return - if index < len(self.current_sentence): + if index <= len(self.current_sentence) and index > 0: - expected_char = self.current_sentence[index] + expected = self.current_sentence[index-1] - if event.char == expected_char: - winsound.Beep(800, 30) # correct key + if typed[-1] == expected: + winsound.Beep(800, 30) else: - winsound.Beep(300, 80) # wrong key + winsound.Beep(300, 80) + + # Finish early if sentence completed + if typed.strip() == self.current_sentence.strip(): + self.check_result() + + # ====================== + # UPDATE STREAKS + # ====================== + + def update_streaks(self, wpm): + + today = datetime.now().date() + last_date = self.data["last_practice_date"] + + if last_date: + last_date = datetime.strptime(last_date, "%Y-%m-%d").date() + + if today == last_date + timedelta(days=1): + self.data["daily_streak"] += 1 + elif today != last_date: + self.data["daily_streak"] = 1 + else: + self.data["daily_streak"] = 1 + + self.data["last_practice_date"] = str(today) + + if wpm > self.data["last_wpm"]: + self.data["improvement_streak"] += 1 + else: + self.data["improvement_streak"] = 0 + + self.data["last_wpm"] = wpm + + if wpm > self.data["best_wpm"]: + self.data["best_wpm"] = wpm + self.data["personal_best_streak"] += 1 + + save_data(self.data) # ====================== # RESULT # ====================== + def check_result(self): if not self.start_time: @@ -248,7 +323,7 @@ def check_result(self): self.timer_running = False - winsound.Beep(1200, 300) # completion sound + winsound.Beep(1200, 300) typed_text = self.input_textbox.get("1.0", "end-1c") @@ -261,10 +336,16 @@ def check_result(self): else: wpm = (chars / 5) / (elapsed_time / 60) + self.update_streaks(wpm) + self.result_label.configure( text=f"Typing Speed: {wpm:.2f} WPM" ) + self.streak_label.configure( + text=self.get_streak_text() + ) + self.input_textbox.configure(state="disabled") self.pause_button.configure(state="disabled") self.start_button.configure(state="normal") From 03e5f4d91e929e11aa10618684f69ec8929e11b3 Mon Sep 17 00:00:00 2001 From: devikrishna111 Date: Thu, 12 Mar 2026 21:57:57 +0530 Subject: [PATCH 3/3] Ignore streak data file --- streak_data.json | 1 - 1 file changed, 1 deletion(-) delete mode 100644 streak_data.json diff --git a/streak_data.json b/streak_data.json deleted file mode 100644 index 54990c5..0000000 --- a/streak_data.json +++ /dev/null @@ -1 +0,0 @@ -{"daily_streak": 1, "last_practice_date": "2026-03-12", "improvement_streak": 2, "personal_best_streak": 2, "best_wpm": 25.100241252979508, "last_wpm": 25.100241252979508} \ No newline at end of file