Skip to content

Practice Timer Implementation #24

@brylie

Description

@brylie

Overview

Implement a practice timer that adapts its display format based on elapsed time (M:SS for sessions under an hour, H:MM:SS for longer sessions). The timer will use a toggle button that switches between play and pause states, creating an intuitive and clean interface for students.

Current State

The specification outlines the need for a basic session timer in Phase 1 (MVP). No timer implementation currently exists.

Requirements

Timer Display

The timer should show elapsed practice time in a format that adapts to the duration:

  • Under 60 minutes: "M:SS" (e.g., "5:23")
  • Over 60 minutes: "H:MM:SS" (e.g., "1:05:23")
  • No leading zeros for the leftmost digit
  • Updates every second while running

Controls

The interface will feature two buttons:

  1. Toggle Button (Play/Pause)

    • Single button that alternates between two states
    • Shows play icon (▶) when timer is paused
    • Shows pause icon (⏸) when timer is running
    • Icon always indicates the next available action
  2. Reset Button

    • Returns timer to 0
    • Enabled only when elapsed time is greater than 0

Technical Implementation

The implementation uses a single boolean state variable to manage the timer's running state, making the code clear and maintainable. Here's the GDScript implementation:

extends Node

# Core state variables
var playing: bool = false
var elapsed_seconds: int = 0

# Preload button textures
@onready var play_texture = preload("res://assets/play_icon.png")
@onready var pause_texture = preload("res://assets/pause_icon.png")

# Node references
@onready var timer: Timer = $Timer
@onready var time_label: Label = $TimeLabel
@onready var toggle_button: TextureButton = $ToggleButton
@onready var reset_button: TextureButton = $ResetButton

func _ready() -> void:
    # Initialize UI state
    update_toggle_button()
    timer.timeout.connect(_on_timer_timeout)
    reset_button.disabled = true

func _on_toggle_pressed() -> void:
    # Toggle between play and pause states
    playing = !playing
    
    # Update timer and button states
    timer.paused = !playing
    update_toggle_button()

func _on_reset_pressed() -> void:
    # Reset timer state
    elapsed_seconds = 0
    playing = false
    
    # Update UI
    update_display()
    update_toggle_button()
    reset_button.disabled = true
    timer.paused = true

func _on_timer_timeout() -> void:
    elapsed_seconds += 1
    update_display()
    reset_button.disabled = false

func update_toggle_button() -> void:
    # Update button icon to show next available action
    toggle_button.texture_normal = pause_texture if playing else play_texture

func update_display() -> void:
    # Format display based on elapsed time
    if elapsed_seconds < 3600:
        # Under one hour: M:SS
        var minutes := elapsed_seconds / 60
        var seconds := elapsed_seconds % 60
        time_label.text = "%d:%02d" % [minutes, seconds]
    else:
        # Over one hour: H:MM:SS
        var hours := elapsed_seconds / 3600
        var minutes := (elapsed_seconds % 3600) / 60
        var seconds := elapsed_seconds % 60
        time_label.text = "%d:%02d:%02d" % [hours, minutes, seconds]

Scene Setup

Create a scene with the following node structure:

Timer (Root Node)
├── Timer (Node)
├── TimeLabel (Label)
├── ToggleButton (TextureButton)
└── ResetButton (TextureButton)

The Timer node should be configured with:

  • One-second timeout
  • Autostart disabled
  • Process mode set to handle pausing

Design Benefits

The toggle button pattern offers several advantages:

  1. Simplified State Management: Using a single playing boolean as the source of truth makes the code easier to maintain and debug. The timer's state is always clear and consistent.

  2. Intuitive User Interface: The button always shows the next available action, making it immediately clear to students what will happen when they click. This reduces the cognitive load during practice sessions.

  3. Clean Code Structure: The toggle pattern clearly identifies the relationship between the user action (button press), state change (playing boolean), and visual feedback (button icon), making the code flow easy to follow.

Testing Requirements

  1. Toggle Functionality

    • Button correctly alternates between play and pause states
    • Icon updates to show the next available action
    • Timer starts and stops appropriately
  2. Timer Display

    • Correct format for times under one hour
    • Proper transition to H:MM:SS at one hour
    • Accurate timekeeping
  3. Reset Functionality

    • Returns to 0 and updates display
    • Disables reset button when timer is at 0
    • Properly resets playing state and button icon

Success Criteria

  • Timer accurately tracks practice time
  • Toggle button provides clear, intuitive control
  • Display format adapts appropriately to elapsed time
  • Interface responds immediately to user input

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions