emulsion 10.0.0

A fast and minimalistic image viewer
use std::rc::{Rc, Weak};

use std::time::{Duration, Instant};

use gelatin::{label::Label, misc::*, picture::Picture, NextUpdate, Widget};

static COPY_STARTED: &[u8] = include_bytes!("../../resource/copy-started.png");
static COPY_READY: &[u8] = include_bytes!("../../resource/copy-ready.png");
static COPY_FAILED: &[u8] = include_bytes!("../../resource/copy-failed.png");

const READY_DISPLAY_TIME: Duration = Duration::from_secs(3);

#[derive(Clone)]
pub struct CopyNotifications {
	pub widget: Weak<Label>,
	copy_started_img: Rc<Picture>,
	copy_ready_img: Rc<Picture>,
	copy_failed_img: Rc<Picture>,
	finished: bool,
	finished_time: std::time::Instant,
}

impl CopyNotifications {
	pub fn new(widget: &Rc<Label>) -> CopyNotifications {
		let copy_started_img = Rc::new(Picture::from_encoded_bytes(COPY_STARTED));
		let copy_ready_img = Rc::new(Picture::from_encoded_bytes(COPY_READY));
		let copy_failed_img = Rc::new(Picture::from_encoded_bytes(COPY_FAILED));

		widget.set_icon(None);
		widget.set_ignore_layout(true);
		widget.set_width(Length::Fixed(128.0));
		widget.set_height(Length::Fixed(32.0));
		widget.set_margin_all(4.0);
		widget.set_horizontal_align(Alignment::End);
		widget.set_vertical_align(Alignment::End);
		widget.set_shadow_size(0.15);
		widget.set_visible(false);

		CopyNotifications {
			widget: Rc::downgrade(widget),
			copy_started_img,
			copy_ready_img,
			copy_failed_img,
			finished: true,
			finished_time: Instant::now(),
		}
	}

	pub fn set_started(&mut self) {
		let widget = self.widget.upgrade().unwrap();
		widget.set_icon(Some(self.copy_started_img.clone()));
		widget.set_visible(true);
		self.finished = false;
	}

	pub fn set_finished(&mut self, succeeded: bool) {
		let widget = self.widget.upgrade().unwrap();
		let icon =
			if succeeded { self.copy_ready_img.clone() } else { self.copy_failed_img.clone() };
		widget.set_icon(Some(icon));
		self.finished_time = Instant::now();
		self.finished = true;
	}

	pub fn update(&mut self) -> NextUpdate {
		let widget = self.widget.upgrade().unwrap();
		if widget.visible() && self.finished {
			let now = Instant::now();
			if now.duration_since(self.finished_time) > READY_DISPLAY_TIME {
				widget.set_visible(false);
				NextUpdate::Latest
			} else {
				NextUpdate::WaitUntil(self.finished_time + READY_DISPLAY_TIME)
			}
		} else {
			NextUpdate::Latest
		}
	}
}