Skip to main content

scrybe_widgets/
view.rs

1// Copyright 2026 Mathews Tom
2// Licensed under the Apache License, Version 2.0 (the "License");
3// you may not use this file except in compliance with the License.
4// You may obtain a copy of the License at
5//     https://www.apache.org/licenses/LICENSE-2.0
6
7//! What every native indicator renders from.
8//!
9//! One rendering-independent snapshot, so the status item, the floating
10//! panel, and anything else showing a live recording cannot disagree
11//! about what they are showing. It carries no dependency on the service
12//! layer: whichever frontend owns a recording projects its own state
13//! model onto this, and the widgets never see a controller.
14
15use std::time::Duration;
16
17/// The recording lifecycle a native indicator shows.
18///
19/// Two states, not six. An indicator the size of a menu-bar item has
20/// room for "this is running" and "this is finishing", and a reader
21/// watching one wants exactly that distinction; the full state model
22/// belongs to the surface that has room to render it.
23#[derive(Copy, Clone, Debug, Eq, PartialEq)]
24pub enum ShellState {
25    Recording,
26    Saving,
27}
28
29/// One snapshot, as every native indicator sees it.
30#[derive(Copy, Clone, Debug, Eq, PartialEq)]
31pub struct ShellView {
32    pub state: ShellState,
33    pub elapsed: Duration,
34    pub stop_enabled: bool,
35}
36
37impl ShellView {
38    /// `HH:MM:SS`, or `MM:SS` under an hour.
39    #[must_use]
40    pub fn elapsed_label(self) -> String {
41        let total_seconds = self.elapsed.as_secs();
42        let seconds = total_seconds % 60;
43        let minutes = (total_seconds / 60) % 60;
44        let hours = total_seconds / 3_600;
45        if hours == 0 {
46            format!("{minutes:02}:{seconds:02}")
47        } else {
48            format!("{hours:02}:{minutes:02}:{seconds:02}")
49        }
50    }
51}