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: DurationThe 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: DurationThe 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
impl Model
Sourcepub fn id(&self) -> i64
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.
Sourcepub fn running(&self) -> bool
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 processedChecking 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 processedIntegration 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:
- Timeout: If the timer has expired (
timedout() == true), it’s not running - Manual State: If manually stopped via
stop(), it’s not running - Default: Otherwise, it follows the internal running flag
§Note
This method matches Go’s Running() method exactly for compatibility.
Sourcepub fn timedout(&self) -> bool
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()returnstruerunning()returnsfalse(expired timers don’t run)- The timer stops processing tick messages automatically
- A
TimeoutMsgis 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.
Sourcepub fn start(&self) -> Cmd
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
start()is called → returnsCmd- Bubble Tea executes the command → generates
StartStopMsg - Message is sent to
update()→ timer state changes to running - 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.
Sourcepub fn stop(&self) -> Cmd
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.
Sourcepub fn toggle(&self) -> Cmd
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()returnstrue→ generates stop command - If
running()returnsfalse→ 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.
Sourcepub fn init(&self) -> Cmd
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:
- Creates the first tick command
- Sets up the timer’s internal tick cycle
- Returns immediately (non-blocking)
- 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.
Sourcepub fn update(&mut self, msg: Msg) -> Option<Cmd>
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 (typicallyTickMsgorStartStopMsg)
§Returns
An optional Cmd for the next timer operation, or None if no action needed
§Message Types Handled
StartStopMsg: Changes the timer’s running stateTickMsg: 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: Changesrunningstate, returns tick commandTickMsg: Reducestimeoutbyinterval, 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:
- Automatically stops running
- May send a
TimeoutMsg(implementation detail) - 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.
Sourcepub fn view(&self) -> String
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 Default for Model
impl Default for Model
Source§fn default() -> Self
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
impl Model for Model
Source§fn init() -> (Self, Option<Cmd>)
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>
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 ticksSource§fn view(&self) -> String
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 Swhere
T: Real + Zero + Arithmetics + Clone,
Swp: WhitePoint<T>,
Dwp: WhitePoint<T>,
D: AdaptFrom<S, Swp, Dwp, T>,
impl<S, D, Swp, Dwp, T> AdaptInto<D, Swp, Dwp, T> for Swhere
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) -> Dwhere
M: TransformMatrix<T>,
fn adapt_into_using<M>(self, method: M) -> Dwhere
M: TransformMatrix<T>,
Source§fn adapt_into(self) -> D
fn adapt_into(self) -> D
Source§impl<T, C> ArraysFrom<C> for Twhere
C: IntoArrays<T>,
impl<T, C> ArraysFrom<C> for Twhere
C: IntoArrays<T>,
Source§fn arrays_from(colors: C) -> T
fn arrays_from(colors: C) -> T
Source§impl<T, C> ArraysInto<C> for Twhere
C: FromArrays<T>,
impl<T, C> ArraysInto<C> for Twhere
C: FromArrays<T>,
Source§fn arrays_into(self) -> C
fn arrays_into(self) -> C
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<WpParam, T, U> Cam16IntoUnclamped<WpParam, T> for Uwhere
T: FromCam16Unclamped<WpParam, U>,
impl<WpParam, T, U> Cam16IntoUnclamped<WpParam, T> for Uwhere
T: FromCam16Unclamped<WpParam, U>,
Source§type Scalar = <T as FromCam16Unclamped<WpParam, U>>::Scalar
type Scalar = <T as FromCam16Unclamped<WpParam, U>>::Scalar
parameters when converting.Source§fn cam16_into_unclamped(
self,
parameters: BakedParameters<WpParam, <U as Cam16IntoUnclamped<WpParam, T>>::Scalar>,
) -> T
fn cam16_into_unclamped( self, parameters: BakedParameters<WpParam, <U as Cam16IntoUnclamped<WpParam, T>>::Scalar>, ) -> T
self into C, using the provided parameters.Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T, C> ComponentsFrom<C> for Twhere
C: IntoComponents<T>,
impl<T, C> ComponentsFrom<C> for Twhere
C: IntoComponents<T>,
Source§fn components_from(colors: C) -> T
fn components_from(colors: C) -> T
Source§impl<T> FromAngle<T> for T
impl<T> FromAngle<T> for T
Source§fn from_angle(angle: T) -> T
fn from_angle(angle: T) -> T
angle.Source§impl<T, U> FromStimulus<U> for Twhere
U: IntoStimulus<T>,
impl<T, U> FromStimulus<U> for Twhere
U: IntoStimulus<T>,
Source§fn from_stimulus(other: U) -> T
fn from_stimulus(other: U) -> T
other into Self, while performing the appropriate scaling,
rounding and clamping.Source§impl<T, U> IntoAngle<U> for Twhere
U: FromAngle<T>,
impl<T, U> IntoAngle<U> for Twhere
U: FromAngle<T>,
Source§fn into_angle(self) -> U
fn into_angle(self) -> U
T.Source§impl<WpParam, T, U> IntoCam16Unclamped<WpParam, T> for Uwhere
T: Cam16FromUnclamped<WpParam, U>,
impl<WpParam, T, U> IntoCam16Unclamped<WpParam, T> for Uwhere
T: Cam16FromUnclamped<WpParam, U>,
Source§type Scalar = <T as Cam16FromUnclamped<WpParam, U>>::Scalar
type Scalar = <T as Cam16FromUnclamped<WpParam, U>>::Scalar
parameters when converting.Source§fn into_cam16_unclamped(
self,
parameters: BakedParameters<WpParam, <U as IntoCam16Unclamped<WpParam, T>>::Scalar>,
) -> T
fn into_cam16_unclamped( self, parameters: BakedParameters<WpParam, <U as IntoCam16Unclamped<WpParam, T>>::Scalar>, ) -> T
self into C, using the provided parameters.Source§impl<T, U> IntoColor<U> for Twhere
U: FromColor<T>,
impl<T, U> IntoColor<U> for Twhere
U: FromColor<T>,
Source§fn into_color(self) -> U
fn into_color(self) -> U
Source§impl<T, U> IntoColorUnclamped<U> for Twhere
U: FromColorUnclamped<T>,
impl<T, U> IntoColorUnclamped<U> for Twhere
U: FromColorUnclamped<T>,
Source§fn into_color_unclamped(self) -> U
fn into_color_unclamped(self) -> U
Source§impl<T> IntoStimulus<T> for T
impl<T> IntoStimulus<T> for T
Source§fn into_stimulus(self) -> T
fn into_stimulus(self) -> T
self into T, while performing the appropriate scaling,
rounding and clamping.Source§impl<T, C> TryComponentsInto<C> for Twhere
C: TryFromComponents<T>,
impl<T, C> TryComponentsInto<C> for Twhere
C: TryFromComponents<T>,
Source§type Error = <C as TryFromComponents<T>>::Error
type Error = <C as TryFromComponents<T>>::Error
try_into_colors fails to cast.Source§fn try_components_into(self) -> Result<C, <T as TryComponentsInto<C>>::Error>
fn try_components_into(self) -> Result<C, <T as TryComponentsInto<C>>::Error>
Source§impl<T, U> TryIntoColor<U> for Twhere
U: TryFromColor<T>,
impl<T, U> TryIntoColor<U> for Twhere
U: TryFromColor<T>,
Source§fn try_into_color(self) -> Result<U, OutOfBounds<U>>
fn try_into_color(self) -> Result<U, OutOfBounds<U>>
OutOfBounds error is returned which contains
the unclamped color. Read more