// Copyright 2024 wiiznokes // SPDX-License-Identifier: MIT use std::time::Duration; use iced::{Command, Length}; use iced_core::{Element}; use crate::widget::container; use crate::widget::Column; use widget::Toaster; use crate::ext::CollectionWidget; use super::{button, row, text}; mod widget; pub fn toaster<'a, Message: Clone + 'a, Theme, Renderer>( toasts: &'a Toasts, content: impl Into>, ) -> Element<'a, Message, Theme, Renderer> where Renderer: iced_core::Renderer, { let make_toast = |toast: &Toast| { let row = row() .push(text(toast.message)) .push_maybe(toast.action.map(|t| button(text(t.0)).on_press(t.1))); container(row) .into() }; let col = Column::with_children(toasts.toasts.iter().map(|t| { make_toast(t) })); Toaster::new(col.into(), content.into()).into() } pub enum ToastDuration { Short, Medium, Long, } impl ToastDuration { fn duration(&self) -> Duration { match self { ToastDuration::Short => Duration::from_millis(200), ToastDuration::Medium => Duration::from_millis(1000), ToastDuration::Long => Duration::from_millis(5000), } } } pub struct Toast { message: String, /// (Description, message) action: Option<(String, Message)>, duration: ToastDuration, id: u32, } pub struct Toasts { id_count: u32, toasts: Vec>, } pub struct ToastMessage(u32); impl Toasts { pub fn push(&mut self, mut toast: Toast) -> Command { toast.id = self.id_count; self.id_count += 1; let message = ToastMessage(toast.id); let duration = toast.duration.duration(); self.toasts.push(toast); Command::perform( async move { tokio::time::sleep(duration).await; }, |_| message, ) } pub fn handle_message(&mut self, message: ToastMessage) { self.toasts .iter() .position(|e| e.id == message.0) .map(|index| self.toasts.remove(index)); } }