use iced_futures::futures; // Just a little utility function pub fn file(url: T) -> iced::Subscription { iced::Subscription::from_recipe(Download { url: url.to_string(), }) } pub struct Download { url: String, } // Make sure iced can use our download stream impl iced_native::subscription::Recipe for Download where H: std::hash::Hasher, { type Output = Progress; fn hash(&self, state: &mut H) { use std::hash::Hash; std::any::TypeId::of::().hash(state); } fn stream( self: Box, _input: futures::stream::BoxStream<'static, I>, ) -> futures::stream::BoxStream<'static, Self::Output> { Box::pin(futures::stream::unfold( State::Ready(self.url), |state| async move { match state { State::Ready(url) => { let response = reqwest::get(&url).await; match response { Ok(response) => Some(( Progress::Started, State::Downloading { total: response.content_length().unwrap(), downloaded: 0, response, }, )), Err(_) => None, } } State::Downloading { mut response, total, downloaded, } => match response.chunk().await { Ok(Some(chunk)) => { let downloaded = downloaded + chunk.len() as u64; let percentage = (downloaded as f32 / total as f32) * 100.0; Some(( Progress::Advanced(percentage), State::Downloading { response, total, downloaded, }, )) } Ok(None) => Some((Progress::Finished, State::Finished)), Err(_) => None, }, State::Finished => None, } }, )) } } #[derive(Debug, Clone)] pub enum Progress { Started, Advanced(f32), Finished, } pub enum State { Ready(String), Downloading { response: reqwest::Response, total: u64, downloaded: u64, }, Finished, }