Use Task::run in download_progress example

This commit is contained in:
Héctor Ramón Jiménez 2024-11-22 02:14:33 +01:00
parent 53b7f507f8
commit 6ccc828607
No known key found for this signature in database
GPG key ID: 7CC46565708259A7
2 changed files with 44 additions and 43 deletions

View file

@ -1,24 +1,13 @@
use iced::futures::{SinkExt, Stream, StreamExt}; use iced::futures::{SinkExt, Stream, StreamExt};
use iced::stream::try_channel; use iced::stream::try_channel;
use iced::Subscription;
use std::hash::Hash;
use std::sync::Arc; use std::sync::Arc;
// Just a little utility function pub fn download(
pub fn file<I: 'static + Hash + Copy + Send + Sync, T: ToString>( url: impl AsRef<str>,
id: I, ) -> impl Stream<Item = Result<Progress, Error>> {
url: T,
) -> iced::Subscription<(I, Result<Progress, Error>)> {
Subscription::run_with_id(
id,
download(url.to_string()).map(move |progress| (id, progress)),
)
}
fn download(url: String) -> impl Stream<Item = Result<Progress, Error>> {
try_channel(1, move |mut output| async move { try_channel(1, move |mut output| async move {
let response = reqwest::get(&url).await?; let response = reqwest::get(url.as_ref()).await?;
let total = response.content_length().ok_or(Error::NoContentLength)?; let total = response.content_length().ok_or(Error::NoContentLength)?;
let _ = output.send(Progress::Downloading { percent: 0.0 }).await; let _ = output.send(Progress::Downloading { percent: 0.0 }).await;

View file

@ -1,7 +1,10 @@
mod download; mod download;
use download::download;
use iced::task;
use iced::widget::{button, center, column, progress_bar, text, Column}; use iced::widget::{button, center, column, progress_bar, text, Column};
use iced::{Center, Element, Right, Subscription}; use iced::{Center, Element, Right, Task};
pub fn main() -> iced::Result { pub fn main() -> iced::Result {
iced::application( iced::application(
@ -9,7 +12,6 @@ pub fn main() -> iced::Result {
Example::update, Example::update,
Example::view, Example::view,
) )
.subscription(Example::subscription)
.run() .run()
} }
@ -23,7 +25,7 @@ struct Example {
pub enum Message { pub enum Message {
Add, Add,
Download(usize), Download(usize),
DownloadProgressed((usize, Result<download::Progress, download::Error>)), DownloadProgressed(usize, Result<download::Progress, download::Error>),
} }
impl Example { impl Example {
@ -34,32 +36,38 @@ impl Example {
} }
} }
fn update(&mut self, message: Message) { fn update(&mut self, message: Message) -> Task<Message> {
match message { match message {
Message::Add => { Message::Add => {
self.last_id += 1; self.last_id += 1;
self.downloads.push(Download::new(self.last_id)); self.downloads.push(Download::new(self.last_id));
Task::none()
} }
Message::Download(index) => { Message::Download(index) => {
if let Some(download) = self.downloads.get_mut(index) { let Some(download) = self.downloads.get_mut(index) else {
download.start(); return Task::none();
} };
let task = download.start();
task.map(move |progress| {
Message::DownloadProgressed(index, progress)
})
} }
Message::DownloadProgressed((id, progress)) => { Message::DownloadProgressed(id, progress) => {
if let Some(download) = if let Some(download) =
self.downloads.iter_mut().find(|download| download.id == id) self.downloads.iter_mut().find(|download| download.id == id)
{ {
download.progress(progress); download.progress(progress);
} }
Task::none()
} }
} }
} }
fn subscription(&self) -> Subscription<Message> {
Subscription::batch(self.downloads.iter().map(Download::subscription))
}
fn view(&self) -> Element<Message> { fn view(&self) -> Element<Message> {
let downloads = let downloads =
Column::with_children(self.downloads.iter().map(Download::view)) Column::with_children(self.downloads.iter().map(Download::view))
@ -90,7 +98,7 @@ struct Download {
#[derive(Debug)] #[derive(Debug)]
enum State { enum State {
Idle, Idle,
Downloading { progress: f32 }, Downloading { progress: f32, _task: task::Handle },
Finished, Finished,
Errored, Errored,
} }
@ -103,14 +111,28 @@ impl Download {
} }
} }
pub fn start(&mut self) { pub fn start(
&mut self,
) -> Task<Result<download::Progress, download::Error>> {
match self.state { match self.state {
State::Idle { .. } State::Idle { .. }
| State::Finished { .. } | State::Finished { .. }
| State::Errored { .. } => { | State::Errored { .. } => {
self.state = State::Downloading { progress: 0.0 }; let (task, handle) = Task::stream(download(
"https://huggingface.co/\
mattshumer/Reflection-Llama-3.1-70B/\
resolve/main/model-00001-of-00162.safetensors",
))
.abortable();
self.state = State::Downloading {
progress: 0.0,
_task: handle.abort_on_drop(),
};
task
} }
State::Downloading { .. } => {} State::Downloading { .. } => Task::none(),
} }
} }
@ -118,7 +140,7 @@ impl Download {
&mut self, &mut self,
new_progress: Result<download::Progress, download::Error>, new_progress: Result<download::Progress, download::Error>,
) { ) {
if let State::Downloading { progress } = &mut self.state { if let State::Downloading { progress, .. } = &mut self.state {
match new_progress { match new_progress {
Ok(download::Progress::Downloading { percent }) => { Ok(download::Progress::Downloading { percent }) => {
*progress = percent; *progress = percent;
@ -133,20 +155,10 @@ impl Download {
} }
} }
pub fn subscription(&self) -> Subscription<Message> {
match self.state {
State::Downloading { .. } => {
download::file(self.id, "https://huggingface.co/mattshumer/Reflection-Llama-3.1-70B/resolve/main/model-00001-of-00162.safetensors")
.map(Message::DownloadProgressed)
}
_ => Subscription::none(),
}
}
pub fn view(&self) -> Element<Message> { pub fn view(&self) -> Element<Message> {
let current_progress = match &self.state { let current_progress = match &self.state {
State::Idle { .. } => 0.0, State::Idle { .. } => 0.0,
State::Downloading { progress } => *progress, State::Downloading { progress, .. } => *progress,
State::Finished { .. } => 100.0, State::Finished { .. } => 100.0,
State::Errored { .. } => 0.0, State::Errored { .. } => 0.0,
}; };