From ab3dc3832277580b4d05c301301f2a34858994d9 Mon Sep 17 00:00:00 2001
From: Ayush Singh <ayush@beagleboard.org>
Date: Tue, 26 Nov 2024 19:04:06 +0530
Subject: [PATCH] gui: Improve cancel messages

- More accurate messages when cancelled by user (seperate for preparation,
  flashing and verification)

Changelog: other
Signed-off-by: Ayush Singh <ayush@beagleboard.org>
---
 gui/src/helpers.rs     | 74 ++++++++++++++++++++++++++++-------
 gui/src/main.rs        | 27 ++++++++-----
 gui/src/pages/flash.rs | 89 ++++++++++++++++++------------------------
 gui/src/pages/mod.rs   |  4 +-
 4 files changed, 115 insertions(+), 79 deletions(-)

diff --git a/gui/src/helpers.rs b/gui/src/helpers.rs
index 7afdea0..e5cb80e 100644
--- a/gui/src/helpers.rs
+++ b/gui/src/helpers.rs
@@ -43,19 +43,28 @@ pub struct ProgressBarState {
     label: Cow<'static, str>,
     progress: f32,
     state: ProgressBarStatus,
+    inner_state: Option<bb_imager::DownloadFlashingStatus>,
 }
 
 impl ProgressBarState {
     pub const FLASHING_SUCCESS: Self =
-        Self::const_new("Flashing Successful", 1.0, ProgressBarStatus::Success);
-    pub const PREPARING: Self = Self::loading("Preparing...");
-    pub const VERIFYING: Self = Self::loading("Verifying...");
-
-    const fn const_new(label: &'static str, progress: f32, state: ProgressBarStatus) -> Self {
+        Self::const_new("Flashing Successful", 1.0, ProgressBarStatus::Success, None);
+    pub const PREPARING: Self =
+        Self::loading("Preparing...", bb_imager::DownloadFlashingStatus::Preparing);
+    pub const VERIFYING: Self =
+        Self::loading("Verifying...", bb_imager::DownloadFlashingStatus::Verifying);
+
+    const fn const_new(
+        label: &'static str,
+        progress: f32,
+        state: ProgressBarStatus,
+        inner_state: Option<bb_imager::DownloadFlashingStatus>,
+    ) -> Self {
         Self {
             label: Cow::Borrowed(label),
             progress,
             state,
+            inner_state,
         }
     }
 
@@ -63,29 +72,40 @@ impl ProgressBarState {
         self.label.to_string()
     }
 
-    fn new(label: impl Into<Cow<'static, str>>, progress: f32, state: ProgressBarStatus) -> Self {
+    fn new(
+        label: impl Into<Cow<'static, str>>,
+        progress: f32,
+        state: ProgressBarStatus,
+        inner_state: Option<bb_imager::DownloadFlashingStatus>,
+    ) -> Self {
         Self {
             label: label.into(),
             progress,
             state,
+            inner_state,
         }
     }
 
     /// Progress should be between 0 to 1.0
-    fn progress(prefix: &'static str, progress: f32) -> Self {
+    fn progress(
+        prefix: &'static str,
+        progress: f32,
+        inner_state: bb_imager::DownloadFlashingStatus,
+    ) -> Self {
         Self::new(
             format!("{prefix}... {}%", (progress * 100.0).round() as usize),
             progress,
             ProgressBarStatus::Normal,
+            Some(inner_state),
         )
     }
 
-    const fn loading(label: &'static str) -> Self {
-        Self::const_new(label, 0.5, ProgressBarStatus::Loading)
+    const fn loading(label: &'static str, inner_state: bb_imager::DownloadFlashingStatus) -> Self {
+        Self::const_new(label, 0.5, ProgressBarStatus::Loading, Some(inner_state))
     }
 
     pub fn fail(label: impl Into<Cow<'static, str>>) -> Self {
-        Self::new(label, 1.0, ProgressBarStatus::Fail)
+        Self::new(label, 1.0, ProgressBarStatus::Fail, None)
     }
 
     pub fn bar(&self) -> widget::Column<'_, BBImagerMessage> {
@@ -104,19 +124,43 @@ impl ProgressBarState {
         .padding(30)
         .spacing(10)
     }
+
+    pub fn cancel(&self) -> Option<Self> {
+        match self.inner_state? {
+            bb_imager::DownloadFlashingStatus::Preparing => {
+                Some(Self::fail("Preparation cancelled by user"))
+            }
+            bb_imager::DownloadFlashingStatus::DownloadingProgress(_) => {
+                Some(Self::fail("Downloading cancelled by user"))
+            }
+            bb_imager::DownloadFlashingStatus::FlashingProgress(_) => {
+                Some(Self::fail("Flashing cancelled by user"))
+            }
+            bb_imager::DownloadFlashingStatus::Verifying
+            | bb_imager::DownloadFlashingStatus::VerifyingProgress(_) => {
+                Some(Self::fail("Verification cancelled by user"))
+            }
+        }
+    }
 }
 
 impl From<bb_imager::DownloadFlashingStatus> for ProgressBarState {
     fn from(value: bb_imager::DownloadFlashingStatus) -> Self {
         match value {
             bb_imager::DownloadFlashingStatus::Preparing => Self::PREPARING,
-            bb_imager::DownloadFlashingStatus::DownloadingProgress(p) => {
-                Self::progress("Downloading Image", p)
-            }
-            bb_imager::DownloadFlashingStatus::FlashingProgress(p) => Self::progress("Flashing", p),
+            bb_imager::DownloadFlashingStatus::DownloadingProgress(p) => Self::progress(
+                "Downloading Image",
+                p,
+                bb_imager::DownloadFlashingStatus::DownloadingProgress(0.0),
+            ),
+            bb_imager::DownloadFlashingStatus::FlashingProgress(p) => Self::progress(
+                "Flashing",
+                p,
+                bb_imager::DownloadFlashingStatus::FlashingProgress(0.0),
+            ),
             bb_imager::DownloadFlashingStatus::Verifying => Self::VERIFYING,
             bb_imager::DownloadFlashingStatus::VerifyingProgress(p) => {
-                Self::progress("Verifying", p)
+                Self::progress("Verifying", p, bb_imager::DownloadFlashingStatus::Verifying)
             }
         }
     }
diff --git a/gui/src/main.rs b/gui/src/main.rs
index 0040a89..a9753cb 100644
--- a/gui/src/main.rs
+++ b/gui/src/main.rs
@@ -61,6 +61,7 @@ struct BBImager {
     search_bar: String,
     cancel_flashing: Option<iced::task::Handle>,
     flashing_config: Option<bb_imager::FlashingConfig>,
+    flashing_state: Option<pages::flash::FlashingState>,
 
     timezones: widget::combo_box::State<String>,
     keymaps: widget::combo_box::State<String>,
@@ -199,10 +200,8 @@ impl BBImager {
                 return Task::batch(jobs.chain([self.refresh_destinations()]));
             }
             BBImagerMessage::ProgressBar(x) => {
-                // Ignore progress bar update if not in the current screen
-                if let Screen::Flashing(s) = self.screen.clone() {
-                    self.screen =
-                        Screen::Flashing(s.update_progress(x, self.cancel_flashing.is_some()))
+                if let Some(state) = self.flashing_state.take() {
+                    self.flashing_state = Some(state.update(x));
                 }
             }
             BBImagerMessage::SelectImage(x) => {
@@ -272,17 +271,22 @@ impl BBImager {
                     task.abort();
                 }
 
-                return Task::done(BBImagerMessage::StopFlashing(ProgressBarState::fail(
-                    "Flashing Cancelled by user",
-                )));
+                if let Some(x) = &self.flashing_state {
+                    if let Some(y) = x.progress.cancel() {
+                        return Task::done(BBImagerMessage::StopFlashing(y));
+                    }
+                }
             }
             BBImagerMessage::StartFlashing => {
                 let docs_url = &self
                     .boards
                     .device(self.selected_board.as_ref().expect("Missing board"))
                     .documentation;
-                self.screen =
-                    Screen::Flashing(pages::flash::FlashingScreen::new(docs_url.to_string()));
+                self.screen = Screen::Flashing;
+                self.flashing_state = Some(pages::flash::FlashingState::new(
+                    ProgressBarState::PREPARING,
+                    docs_url.to_string(),
+                ));
 
                 let dst = self.selected_dst.clone().expect("No destination selected");
                 let img = self.selected_image.clone().expect("Missing os image");
@@ -411,7 +415,10 @@ impl BBImager {
                 &self.timezones,
                 &self.keymaps,
             ),
-            Screen::Flashing(s) => s.view(),
+            Screen::Flashing => pages::flash::view(
+                self.flashing_state.as_ref().unwrap(),
+                self.cancel_flashing.is_some(),
+            ),
         }
     }
 
diff --git a/gui/src/pages/flash.rs b/gui/src/pages/flash.rs
index d55d583..9568206 100644
--- a/gui/src/pages/flash.rs
+++ b/gui/src/pages/flash.rs
@@ -7,70 +7,24 @@ use crate::{
 };
 
 #[derive(Debug, Clone)]
-pub struct FlashingScreen {
-    progress: ProgressBarState,
+pub struct FlashingState {
+    pub(crate) progress: ProgressBarState,
     documentation: String,
-    running: bool,
 }
 
-impl Default for FlashingScreen {
-    fn default() -> Self {
-        FlashingScreen {
-            progress: ProgressBarState::PREPARING,
-            documentation: String::new(),
-            running: true,
-        }
-    }
-}
-
-impl FlashingScreen {
-    pub fn new(documentation: String) -> Self {
+impl FlashingState {
+    pub fn new(progress: ProgressBarState, documentation: String) -> Self {
         Self {
             documentation,
-            ..Default::default()
+            progress,
         }
     }
 
-    pub fn update_progress(mut self, progress: ProgressBarState, running: bool) -> Self {
+    pub fn update(mut self, progress: ProgressBarState) -> Self {
         self.progress = progress;
-        self.running = running;
         self
     }
 
-    pub fn view(&self) -> Element<BBImagerMessage> {
-        widget::responsive(|size| {
-            let prog_bar = self.progress.bar();
-
-            let btn = if self.running {
-                home_btn("CANCEL", true, iced::Length::Shrink)
-                    .on_press(BBImagerMessage::CancelFlashing)
-            } else {
-                home_btn("HOME", true, iced::Length::Shrink)
-                    .on_press(BBImagerMessage::SwitchScreen(Screen::Home))
-            };
-
-            let bottom = widget::container(
-                widget::column![self.about().height(size.height - 410.0), btn, prog_bar]
-                    .width(iced::Length::Fill)
-                    .height(iced::Length::Fill)
-                    .align_x(iced::Alignment::Center),
-            )
-            .style(|_| {
-                widget::container::background(
-                    iced::Color::parse("#aa5137").expect("unexpected error"),
-                )
-            });
-
-            widget::column![helpers::logo(), bottom]
-                .spacing(10)
-                .width(iced::Length::Fill)
-                .height(iced::Length::Fill)
-                .align_x(iced::Alignment::Center)
-                .into()
-        })
-        .into()
-    }
-
     fn about(&self) -> widget::Container<'_, BBImagerMessage> {
         widget::container(widget::scrollable(widget::rich_text![
             widget::span(constants::BEAGLE_BOARD_ABOUT)
@@ -86,3 +40,34 @@ impl FlashingScreen {
         .padding(32)
     }
 }
+
+pub fn view(state: &FlashingState, running: bool) -> Element<BBImagerMessage> {
+    widget::responsive(move |size| {
+        let prog_bar = state.progress.bar();
+
+        let btn = if running {
+            home_btn("CANCEL", true, iced::Length::Shrink).on_press(BBImagerMessage::CancelFlashing)
+        } else {
+            home_btn("HOME", true, iced::Length::Shrink)
+                .on_press(BBImagerMessage::SwitchScreen(Screen::Home))
+        };
+
+        let bottom = widget::container(
+            widget::column![state.about().height(size.height - 410.0), btn, prog_bar]
+                .width(iced::Length::Fill)
+                .height(iced::Length::Fill)
+                .align_x(iced::Alignment::Center),
+        )
+        .style(|_| {
+            widget::container::background(iced::Color::parse("#aa5137").expect("unexpected error"))
+        });
+
+        widget::column![helpers::logo(), bottom]
+            .spacing(10)
+            .width(iced::Length::Fill)
+            .height(iced::Length::Fill)
+            .align_x(iced::Alignment::Center)
+            .into()
+    })
+    .into()
+}
diff --git a/gui/src/pages/mod.rs b/gui/src/pages/mod.rs
index 15f4f2e..112c6ac 100644
--- a/gui/src/pages/mod.rs
+++ b/gui/src/pages/mod.rs
@@ -5,7 +5,7 @@ pub mod flash;
 pub mod home;
 pub mod image_selection;
 
-#[derive(Default, Debug, Clone)]
+#[derive(Default, Debug, Clone, Copy)]
 pub enum Screen {
     #[default]
     Home,
@@ -13,5 +13,5 @@ pub enum Screen {
     ImageSelection,
     DestinationSelection,
     ExtraConfiguration,
-    Flashing(flash::FlashingScreen),
+    Flashing,
 }
-- 
GitLab