8000 Implement tooltips with connection details on the connect buttons on device details by andrewdavidmackenzie · Pull Request #994 · andrewdavidmackenzie/pigg · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Implement tooltips with connection details on the connect buttons on device details #994

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
May 22, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

8000
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
222 changes: 108 additions & 114 deletions piggui/src/views/info_dialog.rs
A708
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ use crate::views::about::REPOSITORY;
use crate::views::dialog_styles::{
cancel_button, connect_button, hyperlink_button, MODAL_CONTAINER_STYLE,
};
use crate::views::hardware_styles::TOOLTIP_STYLE;
use crate::Message;
use iced::keyboard::key;
use iced::widget::{button, column, container, horizontal_space, text, Row, Space, Text};
use iced::widget::tooltip::Position;
use iced::widget::{button, column, container, horizontal_space, text, Row, Space, Text, Tooltip};
use iced::{keyboard, window, Color, Element, Event, Length, Task};
use iced_futures::core::Alignment;
use iced_futures::Subscription;
Expand All @@ -14,11 +16,10 @@ use pignet::HardwareConnection;
use std::collections::HashMap;

pub struct InfoDialog {
show_modal: bool,
is_warning: bool,
modal_type: Option<ModalType>,
hardware_connections: HashMap<String, HardwareConnection>,
modal_type: ModalType,
}

#[derive(PartialEq)]
pub enum ModalType {
Error {
title: &'static str,
Expand All @@ -30,11 +31,16 @@ pub enum ModalType {
body: String,
load_config: bool,
},
Info {
DeviceDetails {
title: String,
body: String,
hardware_connections: HashMap<String, HardwareConnection>,
},
Version {
title: String,
body: String,
is_version: bool,
},
None,
}

const WHITE_TEXT: text::Style = text::Style {
Expand All @@ -59,93 +65,73 @@ pub enum InfoDialogMessage {
impl InfoDialog {
pub fn new() -> Self {
Self {
show_modal: false,
is_warning: false,
modal_type: None,
hardware_connections: HashMap::default(),
modal_type: ModalType::None,
}
}

pub fn showing_modal(&self) -> bool {
self.show_modal
self.modal_type != ModalType::None
}

pub fn update(&mut self, message: InfoDialogMessage) -> Task<Message> {
match message {
InfoDialogMessage::HideModal => {
self.show_modal = false;
self.modal_type = ModalType::None;
Task::none()
}

// Display warning for unsaved changes
InfoDialogMessage::UnsavedChangesExitModal => {
self.show_modal = true;
self.is_warning = true;
self.modal_type = Some(ModalType::Warning {
self.modal_type = ModalType::Warning {
title: "Unsaved Changes".to_string(),
body: "You have unsaved changes. Do you want to exit without saving?"
.to_string(),
load_config: false,
});
};
Task::none()
}

// Display hardware information
#[allow(unused_variables)]
InfoDialogMessage::HardwareDetailsModal(hardware_details, hardware_connections) => {
self.show_modal = true;
self.is_warning = false;
#[allow(unused_mut)]
let mut body = format!("{hardware_details}");

if !hardware_connections.is_empty() {
self.hardware_connections = hardware_connections.clone();
}

self.modal_type = Some(ModalType::Info {
self.modal_type = ModalType::DeviceDetails {
title: "Device Details".to_string(),
body,
is_version: false,
});
body: format!("{hardware_details}\n"),
hardware_connections: hardware_connections.clone(),
};
Task::none()
}

InfoDialogMessage::LoadFile => {
self.show_modal = false;
self.modal_type = ModalType::None;
Task::batch(vec![pick_and_load()])
}

InfoDialogMessage::UnsavedLoadConfigChangesModal => {
self.show_modal = true;
self.modal_type = Some(ModalType::Warning {
self.modal_type = ModalType::Warning {
title: "Unsaved Changes".to_string(),
body: "You have unsaved changes, loading a new config will overwrite them"
.to_string(),
load_config: true,
});
};
Task::none()
}

// Display piggui information
InfoDialogMessage::AboutDialog => {
self.show_modal = true;
self.is_warning = false;
self.modal_type = Some(ModalType::Info {
self.modal_type = ModalType::Version {
title: "About Piggui".to_string(),
body: crate::views::about::about().to_string(),
is_version: true,
});
};
Task::none()
}

InfoDialogMessage::ErrorWithHelp(title, body, help_link) => {
self.show_modal = true;
self.is_warning = false;
self.modal_type = Some(ModalType::Error {
self.modal_type = ModalType::Error {
title,
body,
help_link,
});
};
Task::none()
}

Expand All @@ -164,7 +150,7 @@ impl InfoDialog {
key: keyboard::Key::Named(key::Named::Escape),
..
})) => {
self.show_modal = false;
self.modal_type = ModalType::None;
Task::none()
}
_ => Task::none(),
Expand Down Expand Up @@ -194,11 +180,11 @@ impl InfoDialog {

pub fn view(&self) -> Element<Message> {
match &self.modal_type {
Some(ModalType::Warning {
ModalType::Warning {
title,
body,
load_config,
}) => {
} => {
let text_style = text::Style {
color: Some(Color::new(0.988, 0.686, 0.243, 1.0)),
};
Expand All @@ -222,55 +208,66 @@ impl InfoDialog {

Self::info_container(title, body, button_row, text_style)
}
Some(ModalType::Info {

ModalType::DeviceDetails {
title,
body,
is_version,
}) => {
let mut hyperlink_row = Row::new().width(Length::Fill);
hardware_connections,
} => {
let mut button_row = Row::new();
if *is_version {
hyperlink_row = hyperlink_row.push(Text::new("Full source available at: "));
hyperlink_row = hyperlink_row

button_row = button_row.push(
button("Close")
.on_press(Message::Modal(InfoDialogMessage::HideModal))
.style(cancel_button),
);
for (name, hardware_connection) in hardware_connections {
let button = button(text(format!("Connect via {}", name)))
.on_press(Message::ConnectRequest(hardware_connection.clone()))
.style(connect_button);
button_row = button_row
.push(horizontal_space())
.push(
button(Text::new("github"))
.on_press(Message::Modal(InfoDialogMessage::OpenLink(REPOSITORY)))
.style(hyperlink_button),
Tooltip::new(
button,
text(format!("{hardware_connection}")),
Position::Top,
)
.gap(4.0)
.style(|_| TOOLTIP_STYLE),
)
.align_y(Alignment::Center);
button_row = button_row.push(hyperlink_row);
button_row = button_row.push(
button("Close")
.on_press(Message::Modal(InfoDialogMessage::HideModal))
.style(cancel_button),
);
} else {
button_row = button_row.push(
button("Close")
.on_press(Message::Modal(InfoDialogMessage::HideModal))
.style(cancel_button),
);
for (name, hardware_connection) in &self.hardware_connections {
button_row = button_row
.push(horizontal_space())
.push(
button(text(format!("Connect via {}", name)))
.on_press(Message::ConnectRequest(hardware_connection.clone()))
.style(connect_button),
)
.align_y(Alignment::Center);
}
}

Self::info_container(title, body, button_row, WHITE_TEXT)
}
None => container(column![]).into(), // Render empty container

Some(ModalType::Error {
ModalType::Version { title, body } => {
let mut hyperlink_row = Row::new().width(Length::Fill);
let mut button_row = Row::new();
hyperlink_row = hyperlink_row.push(Text::new("Full source available at: "));
hyperlink_row = hyperlink_row
.push(
button(Text::new("github"))
.on_press(Message::Modal(InfoDialogMessage::OpenLink(REPOSITORY)))
.style(hyperlink_button),
)
.align_y(Alignment::Center);
button_row = button_row.push(hyperlink_row);
button_row = button_row.push(
button("Close")
.on_press(Message::Modal(InfoDialogMessage::HideModal))
.style(cancel_button),
);

Self::info_container(title, body, button_row, WHITE_TEXT)
}

ModalType::Error {
title,
body,
help_link,
}) => {
} => {
let mut button_row = Row::new();
let help_button = button(Text::new("Help"))
.on_press(Message::Modal(InfoDialogMessage::OpenLink(help_link)))
Expand All @@ -284,6 +281,8 @@ impl InfoDialog {

Self::info_container(title, body, button_row, WHITE_TEXT)
}

ModalType::None => container(column![]).into(), // Render empty container
}
}

Expand All @@ -299,38 +298,37 @@ mod tests {
#[test]
fn test_hide_modal() {
let mut display_modal = InfoDialog::new();
display_modal.show_modal = true;
display_modal.modal_type = Some(ModalType::Info {
display_modal.modal_type = ModalType::DeviceDetails {
title: "Test".to_string(),
body: "Test body".to_string(),
is_version: false,
});
hardware_connections: HashMap::new(),
};

let _ = display_modal.update(InfoDialogMessage::HideModal);
assert!(!display_modal.show_modal);
assert!(!display_modal.showing_modal());
}

#[test]
fn test_unsaved_changes_exit_modal() {
let mut display_modal = InfoDialog::new();

let _ = display_modal.update(InfoDialogMessage::UnsavedChangesExitModal);
assert!(display_modal.show_modal);

if let Some(ModalType::Warning {
title,
body,
load_config,
}) = &display_modal.modal_type
{
assert_eq!(title, "Unsaved Changes");
assert_eq!(

match display_modal.modal_type {
ModalType::Warning {
title,
body,
"You have unsaved changes. Do you want to exit without saving?"
);
assert!(!*load_config);
} else {
panic!("ModalType should be Warning");
load_config: _,
} => {
assert_eq!(title, "Unsaved Changes");
assert_eq!(
body,
"You have unsaved changes. Do you want to exit without saving?"
);
}
_ => {
panic!("ModalType should be Warning");
}
}
}

Expand All @@ -339,19 +337,15 @@ mod tests {
let mut display_modal = InfoDialog::new();

let _ = display_modal.update(InfoDialogMessage::AboutDialog);
assert!(display_modal.show_modal);

if let Some(ModalType::Info {
title,
body,
is_version,
}) = &display_modal.modal_type
{
assert!(is_version);
assert_eq!(title, "About Piggui");
assert_eq!(body, &crate::views::about::about().to_string());
} else {
panic!("ModalType should be Info");

match display_modal.modal_type {
ModalType::Version { title, body } => {
assert_eq!(title, "About Piggui");
assert_eq!(body, crate::views::about::about().to_string());
}
_ => {
panic!("ModalType should be Info");
}
}
}
}
1 change: 0 additions & 1 deletion piglet/src/device_net/tcp_device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ pub async fn get_device() -> anyhow::Result<TcpDevice> {
while retry_count < 4 {
println!("Trying to get IP address:");
if let Ok(ip) = local_ip() {
println!("Got IP address:");
let port = pick_unused_port().ok_or(anyhow!("Could not find a free port"))?;
println!("ip: {ip}:{port}");
let address = format!("{}:{}", ip, port);
Expand Down
Loading
Loading
0