1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
use std::time::Duration; use chrono::prelude::*; use failure::ResultExt; use futures::{stream, Future, Stream}; use tokio_timer::Timer; use super::{Widget, WidgetStream}; use crate::text::{Attributes, Text}; use crate::{Cnx, Result}; /// Shows the current time and date. /// /// This widget shows the current time and date, in the form `%Y-%m-%d %a %I:%M /// %p`, e.g. `2017-09-01 Fri 12:51 PM`. pub struct Clock { timer: Timer, attr: Attributes, } impl Clock { /// Creates a new Clock widget. /// /// Creates a new `Clock` widget, whose text will be displayed with the /// given [`Attributes`]. /// /// The [`Cnx`] instance is borrowed during construction in order to get /// access to handles of its event loop. However, it is not borrowed for the /// lifetime of the widget. See the [`cnx_add_widget!()`] for more /// discussion about the lifetime of the borrow. /// /// [`Attributes`]: ../text/struct.Attributes.html /// [`Cnx`]: ../struct.Cnx.html /// [`cnx_add_widget!()`]: ../macro.cnx_add_widget.html /// /// # Examples /// /// ``` /// # #[macro_use] /// # extern crate cnx; /// # /// # use cnx::*; /// # use cnx::text::*; /// # use cnx::widgets::*; /// # /// # fn run() -> ::cnx::Result<()> { /// let attr = Attributes { /// font: Font::new("SourceCodePro 21"), /// fg_color: Color::white(), /// bg_color: None, /// padding: Padding::new(8.0, 8.0, 0.0, 0.0), /// }; /// /// let mut cnx = Cnx::new(Position::Top)?; /// cnx_add_widget!(cnx, Clock::new(&cnx, attr.clone())); /// # Ok(()) /// # } /// # fn main() { run().unwrap(); } /// ``` pub fn new(cnx: &Cnx, attr: Attributes) -> Clock { Clock { timer: cnx.timer(), attr, } } } impl Widget for Clock { fn stream(self: Box<Self>) -> Result<WidgetStream> { // As we're not showing seconds, we can sleep for however long it takes // until the minutes changes between updates. Initially sleep for 0 seconds // so that our `self.timer.sleep()` expires immediately. let sleep_for = Duration::from_secs(0); let stream = stream::unfold(sleep_for, move |sleep_for| { // Avoid having to move self into the .map() closure. let attr = self.attr.clone(); Some(self.timer.sleep(sleep_for).map(move |()| { let now = Local::now(); let formatted = now.format("%Y-%m-%d %a %I:%M %p").to_string(); let texts = vec![Text { attr: attr, text: formatted, stretch: false, }]; let sleep_for = Duration::from_secs(60 - u64::from(now.second())); (texts, sleep_for) })) }) .then(|r| r.context("Error in tokio_timer stream")) .map_err(|e| e.into()); Ok(Box::new(stream)) } }