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}