Model

Struct Model 

Source
pub struct Model {
    pub timeout: Duration,
    pub interval: Duration,
    /* private fields */
}
Expand description

High-precision countdown timer component for Bubble Tea applications.

This struct represents a timer that counts down from an initial timeout value at regular intervals. It provides fine-grained control over timing behavior and integrates seamlessly with the Bubble Tea message-passing architecture.

§Core Features

  • Precise Timing: Configurable tick intervals for smooth countdown display
  • State Management: Start, stop, and toggle operations with proper state tracking
  • Message Filtering: Automatic ID-based filtering prevents cross-timer interference
  • Timeout Detection: Multiple ways to detect and handle timer expiration
  • Go Compatibility: API matches Go’s bubbles timer for easy migration

§Examples

Basic timer usage:

use bubbletea_widgets::timer::{new, new_with_interval};
use std::time::Duration;

// Create a 30-second timer with default 1-second ticks
let timer = new(Duration::from_secs(30));
assert_eq!(timer.timeout, Duration::from_secs(30));
assert!(timer.running());

// Create a timer with custom tick rate
let fast_timer = new_with_interval(
    Duration::from_secs(10),
    Duration::from_millis(100)
);
assert_eq!(fast_timer.interval, Duration::from_millis(100));

Integration with Bubble Tea:

use bubbletea_widgets::timer::{new, Model as TimerModel, TimeoutMsg};
use bubbletea_rs::{Model as BubbleTeaModel, Cmd, Msg};
use std::time::Duration;

struct App {
    timer: TimerModel,
    status: String,
}

impl BubbleTeaModel for App {
    fn init() -> (Self, Option<Cmd>) {
        let timer = new(Duration::from_secs(5));
        let cmd = timer.init();
        (App {
            timer,
            status: "Timer running...".to_string(),
        }, Some(cmd))
    }

    fn update(&mut self, msg: Msg) -> Option<Cmd> {
        // Handle timeout events
        if let Some(timeout) = msg.downcast_ref::<TimeoutMsg>() {
            if timeout.id == self.timer.id() {
                self.status = "Time's up!".to_string();
                return None;
            }
        }
         
        // Forward other messages to timer
        self.timer.update(msg)
    }

    fn view(&self) -> String {
        format!("{} - Remaining: {}", self.status, self.timer.view())
    }
}

§State Management

The timer maintains several important states:

  • Running: Whether the timer is actively counting down
  • Timeout: The remaining time until expiration
  • ID: Unique identifier for message filtering
  • Tag: Internal synchronization for accurate timing

§Thread Safety

The Model struct is Clone and can be safely passed between threads. Each timer instance maintains its own unique ID to prevent conflicts.

§Performance Considerations

  • Faster intervals (< 100ms) provide smoother display but use more CPU
  • Multiple timers can run simultaneously without significant overhead
  • Message filtering ensures efficient processing in complex applications

Fields§

§timeout: Duration

The remaining time until the timer expires.

This value decreases by interval on each tick. When it reaches zero or below, the timer is considered expired and will stop automatically.

§interval: Duration

The time between each timer tick.

This controls how frequently the timer updates its display and sends tick messages. Smaller intervals provide smoother countdown display but consume more resources. Default is 1 second.

Implementations§

Source§

impl Model

Source

pub fn id(&self) -> i64

Returns the unique identifier of this timer instance.

Each timer gets a unique ID when created, allowing multiple timers to coexist in the same application without interfering with each other. This ID is used internally for message filtering and can be used by applications to identify which timer generated specific messages.

§Returns

The unique i64 identifier for this timer

§Examples
use bubbletea_widgets::timer::new;
use std::time::Duration;

let timer1 = new(Duration::from_secs(30));
let timer2 = new(Duration::from_secs(60));

// Each timer has a unique ID
assert_ne!(timer1.id(), timer2.id());
assert!(timer1.id() > 0);
assert!(timer2.id() > 0);

Using ID to identify timer messages:

use bubbletea_widgets::timer::{new, TimeoutMsg};
use bubbletea_rs::{Model as BubbleTeaModel, Msg};
use std::time::Duration;

struct App {
    work_timer: bubbletea_widgets::timer::Model,
    break_timer: bubbletea_widgets::timer::Model,
}

impl BubbleTeaModel for App {
    fn update(&mut self, msg: Msg) -> Option<bubbletea_rs::Cmd> {
        if let Some(timeout) = msg.downcast_ref::<TimeoutMsg>() {
            if timeout.id == self.work_timer.id() {
                // Work period finished
            } else if timeout.id == self.break_timer.id() {
                // Break period finished
            }
        }
        None
    }
     
    // ... other methods
}
§Thread Safety

The ID is assigned atomically during timer creation and remains constant throughout the timer’s lifetime, making it safe to use across threads.

§Note

This method matches Go’s ID() method exactly for compatibility.

Source

pub fn running(&self) -> bool

Returns whether the timer is currently counting down.

A timer is considered running when it’s actively counting down and has not expired. This method returns false if the timer has been manually stopped or if it has reached zero and timed out.

§Returns

true if the timer is actively counting down, false otherwise

§Examples
use bubbletea_widgets::timer::new;
use std::time::Duration;

let mut timer = new(Duration::from_secs(30));

// Timer starts in running state
assert!(timer.running());

// Manually stopping the timer
let _stop_cmd = timer.stop();
// Note: timer.running() would still return true until the stop message is processed

Checking timer state in different scenarios:

use bubbletea_widgets::timer::new;
use std::time::Duration;

let mut timer = new(Duration::from_secs(5));
assert!(timer.running()); // Initially running

// Simulate timer expiration
timer.timeout = Duration::ZERO;
assert!(!timer.running()); // Not running when expired

// Reset timeout but manually stop the timer
timer.timeout = Duration::from_secs(10);
// Use stop() method instead of accessing private field
let _stop_cmd = timer.stop();
// Note: timer.running() may still return true until stop message is processed

Integration with control commands:

use bubbletea_widgets::timer::new;
use std::time::Duration;

let timer = new(Duration::from_secs(60));

// These commands change the running state
let start_cmd = timer.start();   // Will make running() return true
let stop_cmd = timer.stop();     // Will make running() return false
let toggle_cmd = timer.toggle(); // Will flip the running state
§State Priority

The running state is determined by multiple factors in this priority order:

  1. Timeout: If the timer has expired (timedout() == true), it’s not running
  2. Manual State: If manually stopped via stop(), it’s not running
  3. Default: Otherwise, it follows the internal running flag
§Note

This method matches Go’s Running() method exactly for compatibility.

Source

pub fn timedout(&self) -> bool

Returns whether the timer has reached zero and expired.

A timer is considered timed out when its remaining timeout duration has reached zero or below. Once timed out, the timer automatically stops running and will not process further tick messages.

§Returns

true if the timer has expired, false if time remains

§Examples
use bubbletea_widgets::timer::new;
use std::time::Duration;

let mut timer = new(Duration::from_secs(30));

// Timer starts with time remaining
assert!(!timer.timedout());

// Simulate timer expiration
timer.timeout = Duration::ZERO;
assert!(timer.timedout());

Checking expiration in different states:

use bubbletea_widgets::timer::new;
use std::time::Duration;

let mut timer = new(Duration::from_millis(100));

// With remaining time
assert!(!timer.timedout());

// Exactly at zero
timer.timeout = Duration::ZERO;
assert!(timer.timedout());

// Very small remaining time
timer.timeout = Duration::from_nanos(1);
assert!(!timer.timedout());

Using in timeout detection:

use bubbletea_widgets::timer::new;
use std::time::Duration;

let mut timer = new(Duration::from_secs(5));

// Application loop simulation
while !timer.timedout() {
    // Process timer ticks
    // timer.update(tick_msg) would reduce timeout
     
    // Break for this example to avoid infinite loop
    timer.timeout = Duration::ZERO;
}

assert!(timer.timedout());
assert!(!timer.running()); // Timed out timers are not running
§Relationship to Running State

When a timer times out:

  • timedout() returns true
  • running() returns false (expired timers don’t run)
  • The timer stops processing tick messages automatically
  • A TimeoutMsg is typically sent to notify the application
§Precision Note

The timeout check uses Duration::ZERO as the threshold. Due to the discrete nature of tick intervals, the actual remaining time when expiration is detected may be slightly negative (saturated to zero).

§Note

This method matches Go’s Timedout() method exactly for compatibility.

Source

pub fn start(&self) -> Cmd

Generates a command to start or resume the timer.

This method returns a command that, when executed by the Bubble Tea runtime, will send a StartStopMsg to resume the timer’s countdown. If the timer is already running, this has no effect. If the timer has timed out, the command has no effect.

§Returns

A Cmd that will start the timer when executed

§Examples
use bubbletea_widgets::timer::new;
use bubbletea_rs::{Model as BubbleTeaModel, Cmd};
use std::time::Duration;

struct App {
    timer: bubbletea_widgets::timer::Model,
}

impl BubbleTeaModel for App {
    fn init() -> (Self, Option<Cmd>) {
        let timer = new(Duration::from_secs(60));
        // Start the timer immediately
        let start_cmd = timer.start();
        (App { timer }, Some(start_cmd))
    }

    fn update(&mut self, msg: bubbletea_rs::Msg) -> Option<Cmd> {
        // Handle user input to start timer
        // if space_key_pressed {
        //     return Some(self.timer.start());
        // }
         
        self.timer.update(msg)
    }
     
    // ... other methods
}

Manual timer control:

use bubbletea_widgets::timer::new;
use std::time::Duration;

let timer = new(Duration::from_secs(30));

// Generate control commands
let start_cmd = timer.start();  // Resume countdown
let stop_cmd = timer.stop();    // Pause countdown
let toggle_cmd = timer.toggle(); // Toggle running state

// Commands are executed by the Bubble Tea runtime
// The actual state change happens when the StartStopMsg is processed
§Command Execution

The returned command is not executed immediately. Instead, it’s returned to the Bubble Tea runtime, which will execute it asynchronously. The actual state change occurs when the resulting StartStopMsg is processed by the timer’s update() method.

§State Change Sequence
  1. start() is called → returns Cmd
  2. Bubble Tea executes the command → generates StartStopMsg
  3. Message is sent to update() → timer state changes to running
  4. Timer begins processing tick messages and counting down
§No Effect Scenarios

The start command has no effect when:

  • The timer has already timed out (timedout() == true)
  • The timer is already running (redundant operation)
§Note

This method matches Go’s Start() method exactly for compatibility.

Source

pub fn stop(&self) -> Cmd

Generates a command to stop or pause the timer.

This method returns a command that, when executed by the Bubble Tea runtime, will send a StartStopMsg to pause the timer’s countdown. The timer retains its current timeout value and can be resumed later with start(). If the timer has already timed out, this command has no effect.

§Returns

A Cmd that will stop the timer when executed

§Examples
use bubbletea_widgets::timer::new;
use bubbletea_rs::{Model as BubbleTeaModel, Cmd, KeyMsg};
use crossterm::event::{KeyCode, KeyModifiers};
use std::time::Duration;

struct App {
    timer: bubbletea_widgets::timer::Model,
    paused: bool,
}

impl BubbleTeaModel for App {
    fn update(&mut self, msg: bubbletea_rs::Msg) -> Option<Cmd> {
        // Handle spacebar to pause/resume
        if let Some(key) = msg.downcast_ref::<KeyMsg>() {
            if key.key == KeyCode::Char(' ') {
                self.paused = !self.paused;
                return if self.paused {
                    Some(self.timer.stop())
                } else {
                    Some(self.timer.start())
                };
            }
        }
         
        self.timer.update(msg)
    }
     
    // ... other methods
}

Timer control pattern:

use bubbletea_widgets::timer::new;
use std::time::Duration;

let timer = new(Duration::from_secs(300)); // 5 minute timer

// Control commands for different scenarios
let pause_cmd = timer.stop();    // Pause for a break
let resume_cmd = timer.start();  // Resume after break
let toggle_cmd = timer.toggle(); // Quick pause/resume
§Pause vs. Reset

Important distinction:

  • Stop/Pause: Halts countdown but preserves remaining time
  • Reset: Would require creating a new timer with original timeout
use bubbletea_widgets::timer::new;
use std::time::Duration;

let mut timer = new(Duration::from_secs(60));

// Simulate some time passing
timer.timeout = Duration::from_secs(45); // 15 seconds elapsed

// Stopping preserves the remaining 45 seconds
let _stop_cmd = timer.stop();
// timer.timeout is still 45 seconds after stop command is processed

// To reset, create a new timer
let reset_timer = new(Duration::from_secs(60));
§Command Execution

Like all timer control methods, the returned command is executed asynchronously by the Bubble Tea runtime. The actual pause occurs when the StartStopMsg is processed.

§No Effect Scenarios

The stop command has no effect when:

  • The timer has already timed out (timedout() == true)
  • The timer is already stopped (redundant operation)
§Note

This method matches Go’s Stop() method exactly for compatibility.

Source

pub fn toggle(&self) -> Cmd

Generates a command to toggle the timer’s running state.

This method provides a convenient way to switch between running and stopped states. If the timer is currently running, it will be stopped. If it’s stopped, it will be started. This is particularly useful for pause/resume functionality controlled by a single user action.

§Returns

A Cmd that will toggle the timer’s state when executed

§Examples
use bubbletea_widgets::timer::new;
use bubbletea_rs::{Model as BubbleTeaModel, Cmd, KeyMsg};
use crossterm::event::{KeyCode, KeyModifiers};
use std::time::Duration;

struct PomodoroApp {
    work_timer: bubbletea_widgets::timer::Model,
}

impl BubbleTeaModel for PomodoroApp {
    fn init() -> (Self, Option<Cmd>) {
        let timer = new(Duration::from_secs(25 * 60)); // 25 minute work session
        let start_cmd = timer.init();
        (PomodoroApp { work_timer: timer }, Some(start_cmd))
    }

    fn update(&mut self, msg: bubbletea_rs::Msg) -> Option<Cmd> {
        // Spacebar toggles timer
        if let Some(key) = msg.downcast_ref::<KeyMsg>() {
            if key.key == KeyCode::Char(' ') {
                return Some(self.work_timer.toggle());
            }
        }
         
        self.work_timer.update(msg)
    }

    fn view(&self) -> String {
        format!(
            "Work Timer: {}\n\n[SPACE] to {}",
            self.work_timer.view(),
            if self.work_timer.running() { "pause" } else { "resume" }
        )
    }
}

Simple toggle pattern:

use bubbletea_widgets::timer::new;
use std::time::Duration;

let timer = new(Duration::from_secs(120));

// One command handles both pause and resume
let toggle_cmd = timer.toggle();

// Equivalent to:
// if timer.running() {
//     timer.stop()
// } else {
//     timer.start()
// }
§State Determination

The toggle decision is based on the current result of running():

  • If running() returns true → generates stop command
  • If running() returns false → generates start command

This means the toggle respects both manual stops and timeout states:

use bubbletea_widgets::timer::new;
use std::time::Duration;

let mut timer = new(Duration::from_secs(30));

// Normal toggle (running → stopped)
assert!(timer.running());
let _toggle1 = timer.toggle(); // Will stop

// Toggle on expired timer (not running → no effect)
timer.timeout = Duration::ZERO;
assert!(!timer.running()); // Not running due to timeout
let _toggle2 = timer.toggle(); // Will attempt start, but no effect due to timeout
§User Interface Benefits

Toggle is ideal for:

  • Single-key pause/resume (spacebar pattern)
  • Play/pause buttons in UI
  • Touch/click interfaces
  • Reducing cognitive load (one action vs. two separate actions)
§Command Execution

The toggle command evaluates the current state when called, not when executed. The actual state change occurs asynchronously when the resulting StartStopMsg is processed by the timer’s update() method.

§Note

This method matches Go’s Toggle() method exactly for compatibility.

Source

pub fn init(&self) -> Cmd

Initializes the timer and returns the command to start its first tick.

This method should be called once when the timer is first created to begin the countdown process. It generates the initial tick command that starts the timer’s regular interval-based updates.

§Returns

A Cmd that will start the timer’s tick cycle when executed

§Examples
use bubbletea_widgets::timer::new;
use bubbletea_rs::{Model as BubbleTeaModel, Cmd};
use std::time::Duration;

struct App {
    timer: bubbletea_widgets::timer::Model,
}

impl BubbleTeaModel for App {
    fn init() -> (Self, Option<Cmd>) {
        let timer = new(Duration::from_secs(60));
        // Initialize the timer to start ticking
        let timer_cmd = timer.init();
        (App { timer }, Some(timer_cmd))
    }
     
    // ... other methods
}

Multiple timer initialization:

use bubbletea_widgets::timer::new;
use bubbletea_rs::{Model as BubbleTeaModel, Cmd};
use std::time::Duration;

struct MultiTimerApp {
    work_timer: bubbletea_widgets::timer::Model,
    break_timer: bubbletea_widgets::timer::Model,
}

impl BubbleTeaModel for MultiTimerApp {
    fn init() -> (Self, Option<Cmd>) {
        let work_timer = new(Duration::from_secs(25 * 60));
        let break_timer = new(Duration::from_secs(5 * 60));
         
        // Start the work timer initially
        let init_cmd = work_timer.init();
         
        (MultiTimerApp { work_timer, break_timer }, Some(init_cmd))
    }
     
    // ... other methods
}
§When to Call
  • Application startup: In your app’s init() method
  • Timer creation: Immediately after creating a new timer
  • Timer reset: When restarting a timer with new settings
§What It Does

The init() method:

  1. Creates the first tick command
  2. Sets up the timer’s internal tick cycle
  3. Returns immediately (non-blocking)
  4. The actual ticking starts when Bubble Tea executes the command
§Timing Behavior

The first tick occurs after the timer’s interval duration. For example, with a 1-second interval, the first countdown update happens 1 second after the init command is executed.

§Alternative to Start

While start() is used to resume a paused timer, init() is specifically for initial timer setup and should be called once per timer instance.

§Note

This method matches Go’s Init() method exactly for compatibility.

Source

pub fn update(&mut self, msg: Msg) -> Option<Cmd>

Processes messages and updates the timer state.

This method handles all messages related to timer operation, including tick messages that advance the countdown and control messages that change the running state. It should be called from your application’s update loop for proper timer functionality.

§Arguments
  • msg - The message to process (typically TickMsg or StartStopMsg)
§Returns

An optional Cmd for the next timer operation, or None if no action needed

§Message Types Handled
  • StartStopMsg: Changes the timer’s running state
  • TickMsg: Advances the countdown and schedules the next tick
  • Other messages: Ignored (returns None)
§Examples
use bubbletea_widgets::timer::{new, TickMsg, StartStopMsg, TimeoutMsg};
use bubbletea_rs::{Model as BubbleTeaModel, Msg, Cmd};
use std::time::Duration;

struct App {
    timer: bubbletea_widgets::timer::Model,
    status: String,
}

impl BubbleTeaModel for App {
    fn update(&mut self, msg: Msg) -> Option<Cmd> {
        // Handle application-specific timer events
        if let Some(timeout) = msg.downcast_ref::<TimeoutMsg>() {
            if timeout.id == self.timer.id() {
                self.status = "Timer completed!".to_string();
            }
        }
         
        // Forward all messages to timer for processing
        self.timer.update(msg)
    }
     
    // ... other methods
}

Manual message handling:

use bubbletea_widgets::timer::new;
use std::time::Duration;

let mut timer = new(Duration::from_secs(10));

// Start the timer using the public API
let start_cmd = timer.start();
// In a real app, you'd send this command through bubbletea

// Check initial timeout
assert_eq!(timer.timeout(), Duration::from_secs(10));
§Message Filtering

The timer automatically filters messages to ensure it only processes messages intended for it:

  • ID Matching: Only processes messages with matching timer IDs
  • Tag Validation: Rejects tick messages with incorrect tags
  • State Checks: Ignores ticks when not running
use bubbletea_widgets::timer::new;
use std::time::Duration;

let mut timer1 = new(Duration::from_secs(10));
let _timer2 = new(Duration::from_secs(20));

// Start timer1
let _cmd = timer1.start();

// Messages with wrong IDs are ignored
// In a real app, messages are routed by ID
assert_eq!(timer1.timeout, Duration::from_secs(10)); // No change
§State Changes

Different message types cause different state changes:

  • StartStopMsg: Changes running state, returns tick command
  • TickMsg: Reduces timeout by interval, returns next tick command
  • Invalid messages: No state change, returns None
§Timeout Detection

When a tick reduces the timeout to zero or below, the timer:

  1. Automatically stops running
  2. May send a TimeoutMsg (implementation detail)
  3. Returns a tick command that will be ignored (since not running)
§Error Handling

This method never panics and handles invalid messages gracefully by ignoring them and returning None.

§Performance

Message processing is very fast, involving only basic comparisons and arithmetic operations. The method is designed to be called frequently in the Bubble Tea update loop.

§Note

This method matches Go’s Update() method exactly for compatibility.

Source

pub fn view(&self) -> String

Renders the timer as a formatted string showing remaining time.

This method converts the timer’s current timeout duration into a human-readable string using Go’s duration formatting conventions. The output is suitable for direct display in terminal applications.

§Returns

A formatted string representation of the remaining time

§Format Examples

The format matches Go’s Duration.String() output:

  • "5m30s" for 5 minutes 30 seconds
  • "2m" for exactly 2 minutes
  • "45.5s" for 45.5 seconds
  • "750ms" for milliseconds
  • "0s" when expired
§Examples
use bubbletea_widgets::timer::new;
use std::time::Duration;

// Various timer displays
let timer1 = new(Duration::from_secs(90));
assert!(timer1.view().contains("1m"));

let timer2 = new(Duration::from_millis(500));
assert!(timer2.view().contains("500ms"));

let mut timer3 = new(Duration::from_secs(1));
timer3.timeout = Duration::ZERO;
assert_eq!(timer3.view(), "0s");

Integration in UI:

use bubbletea_widgets::timer::new;
use bubbletea_rs::{Model as BubbleTeaModel};
use std::time::Duration;

struct App {
    cooking_timer: bubbletea_widgets::timer::Model,
    recipe: String,
}

impl BubbleTeaModel for App {
    fn view(&self) -> String {
        format!(
            "Cooking: {}\n\nTime remaining: {}\n\n[SPACE] to pause",
            self.recipe,
            self.cooking_timer.view()
        )
    }
     
    // ... other methods
}

Dynamic display updates:

use bubbletea_widgets::timer::new;
use std::time::Duration;

let mut timer = new(Duration::from_secs(125)); // 2m5s

// Display updates as timer counts down
println!("Start: {}", timer.view()); // "2m5s"

// Simulate 30 seconds passing
timer.timeout -= Duration::from_secs(30);
println!("After 30s: {}", timer.view()); // "1m35s"

// Simulate completion
timer.timeout = Duration::ZERO;
println!("Finished: {}", timer.view()); // "0s"
§Precision Display

The display precision depends on the remaining time:

  • Minutes: Shows minutes and seconds (e.g., “3m45s”)
  • Seconds: Shows seconds with decimals if needed (e.g., “1.5s”)
  • Milliseconds: Shows millisecond precision (e.g., “250ms”)
  • Microseconds/Nanoseconds: For very short durations
§Use Cases

Perfect for:

  • Countdown displays in TUIs
  • Progress indicators with time remaining
  • Cooking/work timers
  • Game time limits
  • Session timeouts
§Performance

String formatting is performed on each call, so for high-frequency updates, consider caching the result if the timeout hasn’t changed.

§Localization

The format uses English abbreviations (“m”, “s”, “ms”) and follows Go’s conventions. For different locales, you may need to parse the timeout duration and format it according to local preferences.

§Note

This method matches Go’s View() method exactly for compatibility.

Trait Implementations§

Source§

impl Clone for Model

Source§

fn clone(&self) -> Model

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Model

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for Model

Source§

fn default() -> Self

Creates a timer with sensible default settings.

This implementation provides a standard 60-second timer with 1-second intervals, suitable for most common timing needs. The timer starts in a running state and is ready for immediate use.

§Returns

A new timer configured with default settings

§Examples
use bubbletea_widgets::timer::Model;
use std::time::Duration;

// Create timer with defaults
let timer = Model::default();
assert_eq!(timer.timeout, Duration::from_secs(60));
assert_eq!(timer.interval, Duration::from_secs(1));
assert!(timer.running());
assert!(!timer.timedout());

Using with struct initialization:

use bubbletea_widgets::timer::Model as TimerModel;

struct App {
    timer: TimerModel,
    // other fields...
}

impl Default for App {
    fn default() -> Self {
        Self {
            timer: TimerModel::default(),
            // initialize other fields...
        }
    }
}
§Default Values
  • Timeout: 60 seconds (1 minute)
  • Interval: 1 second (standard clock tick)
  • Running: true (starts immediately)
  • ID: Unique identifier (generated automatically)
§When to Use

Use Default when:

  • You need a quick timer for testing or prototyping
  • 60 seconds is an appropriate duration for your use case
  • You want to rely on struct field defaults in larger structures
  • Building utilities or examples that need reasonable timer behavior

Use new() or new_with_interval() when:

  • You need specific timeout durations
  • Custom tick intervals are required
  • Explicit configuration is preferred for clarity
§Equivalent Creation

This default implementation is equivalent to:

use bubbletea_widgets::timer::new;
use std::time::Duration;

let timer = new(Duration::from_secs(60));
Source§

impl Model for Model

Source§

fn init() -> (Self, Option<Cmd>)

Creates a new timer model with default settings for standalone use.

This implementation provides a default timer configuration suitable for applications that want to use the timer as a standalone component without custom initialization. It creates a 60-second timer with 1-second intervals.

§Returns

A tuple containing the new timer model and its initialization command

§Examples
use bubbletea_widgets::timer::Model as TimerModel;
use bubbletea_rs::{Model as BubbleTeaModel};

// Use timer as a standalone Bubble Tea application
let model = TimerModel::default();
let cmd = model.init();
// Would start a 60-second timer app
§Default Configuration
  • Timeout: 60 seconds
  • Interval: 1 second
  • State: Running (starts immediately)
  • Display: Shows countdown in “1m0s” format
§Note

Most applications will want to use new() or new_with_interval() instead to create timers with specific durations rather than this default.

Source§

fn update(&mut self, msg: Msg) -> Option<Cmd>

Forwards messages to the timer’s update method.

This implementation delegates all message processing to the timer’s own update() method, ensuring consistent behavior whether the timer is used standalone or as part of a larger application.

§Arguments
  • msg - The message to process
§Returns

An optional command for continued timer operation

§Examples
use bubbletea_widgets::timer::Model as TimerModel;
use bubbletea_rs::{Model as BubbleTeaModel};

let mut timer = TimerModel::default();
// Start the timer
let _start_cmd = timer.start();

// In a real app, tick messages are generated automatically
// Timer processes updates and returns commands for next ticks
Source§

fn view(&self) -> String

Renders the timer display using the timer’s view method.

This implementation delegates to the timer’s own view() method, providing a consistent display format regardless of how the timer is integrated into the application.

§Returns

A formatted string showing the remaining time

§Examples
use bubbletea_widgets::timer::Model as TimerModel;
use bubbletea_rs::Model as BubbleTeaModel;

let timer = TimerModel::default();
let display = timer.view();
assert!(display.contains("1m") || display.contains("60s"));

Auto Trait Implementations§

§

impl Freeze for Model

§

impl RefUnwindSafe for Model

§

impl Send for Model

§

impl Sync for Model

§

impl Unpin for Model

§

impl UnwindSafe for Model

Blanket Implementations§

Source§

impl<S, D, Swp, Dwp, T> AdaptInto<D, Swp, Dwp, T> for S
where T: Real + Zero + Arithmetics + Clone, Swp: WhitePoint<T>, Dwp: WhitePoint<T>, D: AdaptFrom<S, Swp, Dwp, T>,

Source§

fn adapt_into_using<M>(self, method: M) -> D
where M: TransformMatrix<T>,

Convert the source color to the destination color using the specified method.
Source§

fn adapt_into(self) -> D

Convert the source color to the destination color using the bradford method by default.
Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T, C> ArraysFrom<C> for T
where C: IntoArrays<T>,

Source§

fn arrays_from(colors: C) -> T

Cast a collection of colors into a collection of arrays.
Source§

impl<T, C> ArraysInto<C> for T
where C: FromArrays<T>,

Source§

fn arrays_into(self) -> C

Cast this collection of arrays into a collection of colors.
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<WpParam, T, U> Cam16IntoUnclamped<WpParam, T> for U
where T: FromCam16Unclamped<WpParam, U>,

Source§

type Scalar = <T as FromCam16Unclamped<WpParam, U>>::Scalar

The number type that’s used in parameters when converting.
Source§

fn cam16_into_unclamped( self, parameters: BakedParameters<WpParam, <U as Cam16IntoUnclamped<WpParam, T>>::Scalar>, ) -> T

Converts self into C, using the provided parameters.
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T, C> ComponentsFrom<C> for T
where C: IntoComponents<T>,

Source§

fn components_from(colors: C) -> T

Cast a collection of colors into a collection of color components.
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> FromAngle<T> for T

Source§

fn from_angle(angle: T) -> T

Performs a conversion from angle.
Source§

impl<T, U> FromStimulus<U> for T
where U: IntoStimulus<T>,

Source§

fn from_stimulus(other: U) -> T

Converts other into Self, while performing the appropriate scaling, rounding and clamping.
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> IntoAngle<U> for T
where U: FromAngle<T>,

Source§

fn into_angle(self) -> U

Performs a conversion into T.
Source§

impl<WpParam, T, U> IntoCam16Unclamped<WpParam, T> for U
where T: Cam16FromUnclamped<WpParam, U>,

Source§

type Scalar = <T as Cam16FromUnclamped<WpParam, U>>::Scalar

The number type that’s used in parameters when converting.
Source§

fn into_cam16_unclamped( self, parameters: BakedParameters<WpParam, <U as IntoCam16Unclamped<WpParam, T>>::Scalar>, ) -> T

Converts self into C, using the provided parameters.
Source§

impl<T, U> IntoColor<U> for T
where U: FromColor<T>,

Source§

fn into_color(self) -> U

Convert into T with values clamped to the color defined bounds Read more
Source§

impl<T, U> IntoColorUnclamped<U> for T
where U: FromColorUnclamped<T>,

Source§

fn into_color_unclamped(self) -> U

Convert into T. The resulting color might be invalid in its color space Read more
Source§

impl<T> IntoStimulus<T> for T

Source§

fn into_stimulus(self) -> T

Converts self into T, while performing the appropriate scaling, rounding and clamping.
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, C> TryComponentsInto<C> for T
where C: TryFromComponents<T>,

Source§

type Error = <C as TryFromComponents<T>>::Error

The error for when try_into_colors fails to cast.
Source§

fn try_components_into(self) -> Result<C, <T as TryComponentsInto<C>>::Error>

Try to cast this collection of color components into a collection of colors. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T, U> TryIntoColor<U> for T
where U: TryFromColor<T>,

Source§

fn try_into_color(self) -> Result<U, OutOfBounds<U>>

Convert into T, returning ok if the color is inside of its defined range, otherwise an OutOfBounds error is returned which contains the unclamped color. Read more
Source§

impl<C, U> UintsFrom<C> for U
where C: IntoUints<U>,

Source§

fn uints_from(colors: C) -> U

Cast a collection of colors into a collection of unsigned integers.
Source§

impl<C, U> UintsInto<C> for U
where C: FromUints<U>,

Source§

fn uints_into(self) -> C

Cast this collection of unsigned integers into a collection of colors.