watchface/
textual_time_watchface.rs1use crate::battery::ChargerState;
19use crate::styled::Styled;
20use crate::time::Time;
21use crate::Watchface;
22use core::fmt::Write;
23use core::marker::PhantomData;
24
25use embedded_graphics::draw_target::DrawTarget;
26use embedded_graphics::geometry::Point;
27use embedded_graphics::mono_font::{
28 ascii::{FONT_10X20, FONT_9X15_BOLD},
29 MonoTextStyleBuilder,
30};
31use embedded_graphics::pixelcolor::RgbColor;
32use embedded_graphics::text::Text;
33use embedded_graphics::Drawable;
34use embedded_layout::layout::linear::LinearLayout;
35use embedded_layout::prelude::*;
36use heapless::consts::*;
37use heapless::String;
38
39fn convert_hours_to_text(hours: u8) -> &'static str {
40 match hours % 12 {
41 0 => "twaalf",
42 1 => "één",
43 2 => "twee",
44 3 => "drie",
45 4 => "vier",
46 5 => "vijf",
47 6 => "zes",
48 7 => "zeven",
49 8 => "acht",
50 9 => "negen",
51 10 => "tien",
52 11 => "elf",
53 _ => "",
54 }
55}
56
57fn convert_time_to_text(time: &Time) -> String<U20> {
58 let mut text = String::<U20>::new();
59
60 let rounded_time = time.round_to_quarters();
61 if rounded_time.minutes_local() == 0 {
62 write!(
63 &mut text,
64 "{}\nuur",
65 convert_hours_to_text(rounded_time.hours_local())
66 )
67 .unwrap()
68 } else if rounded_time.minutes_local() == 15 {
69 write!(
70 &mut text,
71 "kwart\nover\n{}",
72 convert_hours_to_text(rounded_time.hours_local())
73 )
74 .unwrap()
75 } else if rounded_time.minutes_local() == 30 {
76 write!(
77 &mut text,
78 "half\n{}",
79 convert_hours_to_text(rounded_time.hours_local() + 1)
80 )
81 .unwrap()
82 } else if rounded_time.minutes_local() == 45 {
83 write!(
84 &mut text,
85 "kwart\nvoor\n{}",
86 convert_hours_to_text(rounded_time.hours_local() + 1)
87 )
88 .unwrap()
89 }
90
91 text
92}
93
94#[derive(Default)]
95pub struct TextualTimeWatchfaceStyle<C> {
96 _phantom_data: PhantomData<C>,
97}
98
99impl<C> Drawable for Styled<Watchface, TextualTimeWatchfaceStyle<C>>
100where
101 C: RgbColor,
102{
103 type Color = C;
104
105 type Output = ();
106
107 fn draw<D: DrawTarget<Color = C>>(
108 &self,
109 display: &mut D,
110 ) -> Result<(), <D as DrawTarget>::Error> {
111 let display_area = display.bounding_box();
112
113 display.clear(C::BLACK)?;
114
115 if let Some(time) = &self.watchface.time {
116 let time_text_style = MonoTextStyleBuilder::new()
117 .font(&FONT_10X20)
118 .text_color(C::WHITE)
119 .background_color(C::BLACK)
120 .build();
121
122 let text = convert_time_to_text(time);
123
124 Text::new(&text, Point::new(10, 70), time_text_style)
125 .align_to(&display_area, horizontal::Center, vertical::Center)
126 .draw(display)?;
127 }
128
129 let battery_text = if let Some(battery) = &self.watchface.battery {
130 let mut battery_text = String::<U12>::new();
131 write!(&mut battery_text, "{:02}%", battery.percentage()).unwrap();
132 battery_text
133 } else {
134 String::<U12>::new()
135 };
136
137 let charger_text = match &self.watchface.charger {
138 Some(ChargerState::Charging) => "Charging",
139 Some(ChargerState::Full) => "Full",
140 Some(ChargerState::Discharging) => "",
141 None => "",
142 };
143
144 let text_style = MonoTextStyleBuilder::new()
145 .font(&FONT_9X15_BOLD)
146 .text_color(C::WHITE)
147 .build();
148
149 LinearLayout::vertical(
150 Chain::new(Text::new(
151 battery_text.as_str(),
152 Point::zero(),
153 text_style.clone(),
154 ))
155 .append(Text::new(charger_text, Point::zero(), text_style)),
156 )
157 .with_alignment(horizontal::Right)
158 .arrange()
159 .align_to(&display_area, horizontal::Right, vertical::Top)
160 .draw(display)?;
161
162 Ok(())
163 }
164}