Skip to main content

kasl/libs/
pause.rs

1//! Pause data management and formatting utilities.
2//!
3//! Provides the core data structures and formatting functionality for handling
4//! break periods detected by the activity monitor.
5//!
6//! ## Features
7//!
8//! - **Data Modeling**: Represents pause periods with precise timing information
9//! - **Display Formatting**: Converts raw pause data into human-readable formats
10//! - **Collection Processing**: Batch operations on pause collections
11//! - **Report Integration**: Provides data structures suitable for reporting systems
12//!
13//! ## Usage
14//!
15//! ```rust,no_run
16//! # fn f() -> Result<(), chrono::ParseError> {
17//! use kasl::libs::pause::Pause;
18//! use chrono::{NaiveDateTime, Duration};
19//!
20//! let pause = Pause::detected(
21//!     1,
22//!     NaiveDateTime::parse_from_str("2025-08-11 09:15:00", "%Y-%m-%d %H:%M:%S")?,
23//!     Some(NaiveDateTime::parse_from_str("2025-08-11 09:30:00", "%Y-%m-%d %H:%M:%S")?),
24//!     Some(Duration::minutes(15)),
25//! );
26//! # Ok(())
27//! # }
28//! ```
29
30use chrono::{Duration, prelude::NaiveDateTime};
31
32/// Represents a single pause period with complete timing information.
33///
34/// This structure models a break period detected by the activity monitor,
35/// containing all necessary information for analysis, reporting, and display.
36/// It handles both active (ongoing) and completed pause periods gracefully.
37///
38/// ## Field Semantics
39///
40/// - **`id`**: Unique database identifier for pause tracking and updates
41/// - **`start`**: Precise timestamp when inactivity threshold was reached
42/// - **`end`**: Completion timestamp (None for ongoing pauses)
43/// - **`duration`**: Calculated break duration (None for ongoing pauses)
44///
45/// ## State Handling
46///
47/// The structure supports two primary states:
48///
49/// ### Completed Pause
50/// - All fields populated with meaningful values
51/// - `end` contains actual completion timestamp
52/// - `duration` contains calculated break duration
53/// - Ready for reporting and analysis
54///
55/// ### Ongoing Pause (Active)
56/// - `start` field contains pause initiation time
57/// - `end` field is None (pause still in progress)
58/// - `duration` field is None (cannot calculate until completion)
59/// - Can be displayed with special formatting for active state
60///
61/// ## Duration Calculation
62///
63/// Durations are calculated and stored at the database level for consistency:
64/// - **Precision**: Calculated to the second for accurate reporting
65/// - **Storage**: Stored as seconds in database, converted to Duration for display
66/// - **Consistency**: All duration calculations use same algorithm
67/// - **Timezone**: Uses local time for user-friendly display
68///
69/// ## Display Considerations
70///
71/// The structure is designed for easy formatting:
72/// - Timestamps use standard format suitable for parsing
73/// - Duration is compatible with `chrono::Duration` formatting utilities
74/// - None values are handled gracefully in display formatting
75/// - Supports both detailed and summary display modes
76#[derive(Debug, Clone)]
77pub struct Pause {
78    /// The unique identifier for the pause record in the database.
79    ///
80    /// This ID is auto-generated when the pause record is created and
81    /// serves as the primary key for all database operations. It's used
82    /// for updating pause records when they end and for referencing
83    /// specific pauses in reports and analysis.
84    pub id: i32,
85
86    /// The timestamp when the pause period began.
87    ///
88    /// This represents the precise moment when the activity monitor
89    /// detected that the user had been inactive for the configured
90    /// pause threshold duration. The timestamp uses local time zone
91    /// for user-friendly display and reporting.
92    ///
93    /// ## Precision
94    /// - Stored with second-level precision in the database
95    /// - Captured when inactivity threshold is first exceeded
96    /// - Uses system local time for consistency with user expectations
97    pub start: NaiveDateTime,
98
99    /// The timestamp when the pause period ended.
100    ///
101    /// This field is populated when user activity resumes after a break.
102    /// It remains None for ongoing pauses that haven't completed yet.
103    ///
104    /// ## State Semantics
105    /// - **Some(timestamp)**: Pause has completed, duration can be calculated
106    /// - **None**: Pause is still active, user hasn't returned yet
107    ///
108    /// ## Update Process
109    /// The field is updated when the monitor detects resumed activity:
110    /// 1. Activity monitor detects keyboard/mouse input
111    /// 2. Database record is updated with current timestamp
112    /// 3. Duration is calculated and stored simultaneously
113    pub end: Option<NaiveDateTime>,
114
115    /// The calculated duration of the pause period.
116    ///
117    /// This represents the total time the user was away from the computer
118    /// during this break period. The duration is calculated automatically
119    /// when the pause ends and stored for efficient reporting.
120    ///
121    /// ## Calculation Details
122    /// - **Formula**: `end_time - start_time`
123    /// - **Precision**: Second-level accuracy for detailed analysis
124    /// - **Storage**: Converted from seconds to Duration for easy manipulation
125    /// - **Filtering**: Only pauses meeting minimum duration are typically displayed
126    ///
127    /// ## None Handling
128    /// The field is None for ongoing pauses where the end time hasn't been
129    /// determined yet. Display formatting handles this gracefully by showing
130    /// placeholder values or real-time duration calculation.
131    pub duration: Option<Duration>,
132
133    /// Whether this pause was entered manually and must be preserved as-is.
134    ///
135    /// Protected pauses are recorded by the user through `kasl pauses add`
136    /// rather than detected by the activity monitor. They are exempt from the
137    /// minimum-duration threshold and are never merged with adjacent pauses,
138    /// so a deliberately short entry (a ten-minute walk the monitor missed)
139    /// survives filtering intact.
140    pub protected: bool,
141}
142
143impl Pause {
144    /// Builds a monitor-detected pause (not protected).
145    ///
146    /// Used when reconstructing pauses from sources that carry no protection
147    /// flag, such as in-memory analysis of activity data.
148    pub fn detected(id: i32, start: NaiveDateTime, end: Option<NaiveDateTime>, duration: Option<Duration>) -> Self {
149        Self {
150            id,
151            start,
152            end,
153            duration,
154            protected: false,
155        }
156    }
157}