livesplit_core/component/
total_playtime.rs

1//! Provides the Total Playtime Component and relevant types for using it. The
2//! Total Playtime is a component that shows the total amount of time that the
3//! current category has been played for.
4
5use super::key_value;
6use crate::{
7    analysis::total_playtime,
8    platform::prelude::*,
9    settings::{Color, Field, Gradient, SettingsDescription, Value},
10    timing::formatter::{Days, Regular, TimeFormatter},
11    Timer,
12};
13use core::fmt::Write;
14use serde::{Deserialize, Serialize};
15
16/// The Total Playtime Component is a component that shows the total amount of
17/// time that the current category has been played for.
18#[derive(Default, Clone)]
19pub struct Component {
20    settings: Settings,
21}
22
23/// The Settings for this component.
24#[derive(Clone, Serialize, Deserialize)]
25#[serde(default)]
26pub struct Settings {
27    /// The background shown behind the component.
28    pub background: Gradient,
29    /// Specifies whether to display the name of the component and its value in
30    /// two separate rows.
31    pub display_two_rows: bool,
32    /// Specifies whether the component should show the amount of days, when the
33    /// total duration reaches 24 hours or more.
34    pub show_days: bool,
35    /// The color of the label. If `None` is specified, the color is taken from
36    /// the layout.
37    pub label_color: Option<Color>,
38    /// The color of the value. If `None` is specified, the color is taken from
39    /// the layout.
40    pub value_color: Option<Color>,
41}
42
43impl Default for Settings {
44    fn default() -> Self {
45        Self {
46            background: key_value::DEFAULT_GRADIENT,
47            display_two_rows: false,
48            show_days: true,
49            label_color: None,
50            value_color: None,
51        }
52    }
53}
54
55impl Component {
56    /// Creates a new Total Playtime Component.
57    pub fn new() -> Self {
58        Default::default()
59    }
60
61    /// Creates a new Total Playtime Component with the given settings.
62    pub const fn with_settings(settings: Settings) -> Self {
63        Self { settings }
64    }
65
66    /// Accesses the settings of the component.
67    pub const fn settings(&self) -> &Settings {
68        &self.settings
69    }
70
71    /// Grants mutable access to the settings of the component.
72    pub fn settings_mut(&mut self) -> &mut Settings {
73        &mut self.settings
74    }
75
76    /// Accesses the name of the component.
77    pub const fn name(&self) -> &'static str {
78        "Total Playtime"
79    }
80
81    /// Updates the component's state based on the timer provided.
82    pub fn update_state(&self, state: &mut key_value::State, timer: &Timer) {
83        let total_playtime = total_playtime::calculate(timer);
84
85        state.background = self.settings.background;
86        state.key_color = self.settings.label_color;
87        state.value_color = self.settings.value_color;
88        state.semantic_color = Default::default();
89
90        state.key.clear();
91        state.key.push_str("Total Playtime");
92
93        state.value.clear();
94        if self.settings.show_days {
95            let _ = write!(state.value, "{}", Days::new().format(total_playtime));
96        } else {
97            let _ = write!(state.value, "{}", Regular::new().format(total_playtime));
98        }
99
100        state.key_abbreviations.clear();
101        state.key_abbreviations.push("Playtime".into());
102
103        state.display_two_rows = self.settings.display_two_rows;
104        state.updates_frequently = timer.current_phase().is_running();
105    }
106
107    /// Calculates the component's state based on the timer provided.
108    pub fn state(&self, timer: &Timer) -> key_value::State {
109        let mut state = Default::default();
110        self.update_state(&mut state, timer);
111        state
112    }
113
114    /// Accesses a generic description of the settings available for this
115    /// component and their current values.
116    pub fn settings_description(&self) -> SettingsDescription {
117        SettingsDescription::with_fields(vec![
118            Field::new("Background".into(), self.settings.background.into()),
119            Field::new(
120                "Display 2 Rows".into(),
121                self.settings.display_two_rows.into(),
122            ),
123            Field::new("Show Days (>24h)".into(), self.settings.show_days.into()),
124            Field::new("Label Color".into(), self.settings.label_color.into()),
125            Field::new("Value Color".into(), self.settings.value_color.into()),
126        ])
127    }
128
129    /// Sets a setting's value by its index to the given value.
130    ///
131    /// # Panics
132    ///
133    /// This panics if the type of the value to be set is not compatible with
134    /// the type of the setting's value. A panic can also occur if the index of
135    /// the setting provided is out of bounds.
136    pub fn set_value(&mut self, index: usize, value: Value) {
137        match index {
138            0 => self.settings.background = value.into(),
139            1 => self.settings.display_two_rows = value.into(),
140            2 => self.settings.show_days = value.into(),
141            3 => self.settings.label_color = value.into(),
142            4 => self.settings.value_color = value.into(),
143            _ => panic!("Unsupported Setting Index"),
144        }
145    }
146}