Notification with link to connect

hypertext in upload progress notification

load default url if printer page fails
This commit is contained in:
David Kocik 2024-08-05 17:30:16 +02:00 committed by Lukas Matena
parent c16f2f1c1e
commit 891b6a4816
11 changed files with 150 additions and 63 deletions

View File

@ -841,6 +841,14 @@ void MainFrame::remove_connect_webview_tab()
m_connect_webview->logout();
}
void MainFrame::show_connect_tab(const wxString& url)
{
assert(m_connect_webview_added);
m_tabpanel->SetSelection(m_tabpanel->FindPage(m_connect_webview));
m_connect_webview->set_load_default_url_on_next_error(true);
m_connect_webview->load_url(url);
}
void MainFrame::show_printer_webview_tab(DynamicPrintConfig* dpc)
{
// if physical printer is selected

View File

@ -216,6 +216,7 @@ public:
void add_connect_webview_tab();
void remove_connect_webview_tab();
void show_connect_tab(const wxString &url);
void show_printer_webview_tab(DynamicPrintConfig* dpc);

View File

@ -289,7 +289,7 @@ void NotificationManager::PopNotification::count_lines()
return;
m_endlines.clear();
while (last_end < text.length() - 1)
while (last_end < text.size() - 1)
{
size_t next_hard_end = text.find_first_of('\n', last_end);
if (next_hard_end != std::string::npos && ImGui::CalcTextSize(text.substr(last_end, next_hard_end - last_end).c_str()).x < m_window_width - m_window_width_offset) {
@ -302,14 +302,14 @@ void NotificationManager::PopNotification::count_lines()
if (ImGui::CalcTextSize(text.substr(last_end).c_str()).x >= m_window_width - m_window_width_offset) {
// more than one line till end
size_t next_space = text.find_first_of(' ', last_end);
if (next_space > 0 && next_space < text.length()) {
if (next_space > 0 && next_space < text.size()) {
size_t next_space_candidate = text.find_first_of(' ', next_space + 1);
while (next_space_candidate > 0 && ImGui::CalcTextSize(text.substr(last_end, next_space_candidate - last_end).c_str()).x < m_window_width - m_window_width_offset) {
next_space = next_space_candidate;
next_space_candidate = text.find_first_of(' ', next_space + 1);
}
} else {
next_space = text.length();
next_space = text.size();
}
// when one word longer than line.
if (ImGui::CalcTextSize(text.substr(last_end, next_space - last_end).c_str()).x > m_window_width - m_window_width_offset ||
@ -328,8 +328,8 @@ void NotificationManager::PopNotification::count_lines()
}
}
else {
m_endlines.push_back(text.length());
last_end = text.length();
m_endlines.push_back(text.size());
last_end = text.size();
}
}
@ -370,7 +370,7 @@ void NotificationManager::PopNotification::count_lines()
m_endlines2.push_back(0);
size_of_last_line = 0;
}
while (last_end < text.length() - 1)
while (last_end < text.size() - 1)
{
size_t next_hard_end = text.find_first_of('\n', last_end);
if (next_hard_end != std::string::npos && ImGui::CalcTextSize(text.substr(last_end, next_hard_end - last_end).c_str()).x < m_window_width - m_window_width_offset - size_of_last_line) {
@ -391,7 +391,7 @@ void NotificationManager::PopNotification::count_lines()
}
}
else {
next_space = text.length();
next_space = text.size();
}
// when one word longer than line.
if (ImGui::CalcTextSize(text.substr(last_end, next_space - last_end).c_str()).x > m_window_width - m_window_width_offset - size_of_last_line ||
@ -411,8 +411,8 @@ void NotificationManager::PopNotification::count_lines()
}
}
else {
m_endlines2.push_back(text.length());
last_end = text.length();
m_endlines2.push_back(text.size());
last_end = text.size();
}
}
@ -466,7 +466,7 @@ void NotificationManager::PopNotification::render_text(const float win_size_x, c
assert(m_normal_lines_count - 2 >= 0);
line = m_text1.substr(m_endlines[m_normal_lines_count - 2] + (m_text1[m_endlines[m_normal_lines_count - 2]] == '\n' || m_text1[m_endlines[m_normal_lines_count - 2]] == ' ' ? 1 : 0), m_endlines[m_normal_lines_count - 1] - m_endlines[m_normal_lines_count - 2] - (m_text1[m_endlines[m_normal_lines_count - 2]] == '\n' || m_text1[m_endlines[m_normal_lines_count - 2]] == ' ' ? 1 : 0));
while (ImGui::CalcTextSize(line.c_str()).x > m_window_width - m_window_width_offset - ImGui::CalcTextSize((" [" + _u8L("More") + "]").c_str()).x) {
line = line.substr(0, line.length() - 1);
line = line.substr(0, line.size() - 1);
}
line += " ";//"..";
}
@ -1261,11 +1261,11 @@ void NotificationManager::URLDownloadNotification::render_bar(const float win_si
std::string line = text;
bool did_shorten = false;
while (ImGui::CalcTextSize(line.c_str()).x > m_window_width - m_window_width_offset) {
line = line.substr(0, line.length() - 1);
line = line.substr(0, line.size() - 1);
did_shorten = true;
}
if (did_shorten && dots) {
line = line.substr(0, line.length() - 2);
line = line.substr(0, line.size() - 2);
line += "...";
}
return line;
@ -1346,47 +1346,61 @@ bool NotificationManager::PrintHostUploadNotification::push_background_color()
void NotificationManager::PrintHostUploadNotification::generate_text()
{
auto shorten_to_line = [this](const std::string& text, bool dots) -> std::string {
auto shorten_to_line = [this](const std::string& text, const std::string& endline) -> std::string {
std::string line = text;
bool did_shorten = false;
while (ImGui::CalcTextSize(line.c_str()).x > m_window_width - m_window_width_offset) {
line = line.substr(0, line.length() - 1);
float endline_width = ImGui::CalcTextSize(endline.c_str()).x;
while (ImGui::CalcTextSize(line.c_str()).x > m_window_width - m_window_width_offset - endline_width) {
line = line.substr(0, line.size() - 1);
did_shorten = true;
}
if (did_shorten && dots) {
line = line.substr(0, line.length() - 2);
line += "...";
if (did_shorten && endline.size() != 0) {
line = line.substr(0, line.size() - endline.size());
line += endline;
}
return line;
};
// whole text is no longer than 2 lines, filename is max 1 line long.
std::string rest = " -> " + (m_original_host == m_host ? m_host : m_host + " (" + m_original_host + ")");
std::string line1;
if (ImGui::CalcTextSize(m_filename.c_str()).x > m_window_width - m_window_width_offset) {
line1 = shorten_to_line(m_filename, true);
} else {
line1 = shorten_to_line(m_filename + rest, false);
size_t over = line1.size() - m_filename.size();
if (over < 0)
over = 0;
if (over < rest.size())
rest = rest.substr(over);
else if (over >= rest.size())
rest.clear();
}
std::string line2 = shorten_to_line(rest, true);
if (m_hypertext_override) {
// always divide text into two lines if hypertext. second line is hypertext
m_normal_lines_count = 3;
std::string line1 = shorten_to_line(m_filename + "", "… →");
if (m_uj_state == UploadJobState::PB_COMPLETED || m_uj_state == UploadJobState::PB_COMPLETED_WITH_WARNING) {
m_text1 = line1;
m_hypertext = m_original_host;
m_text2 = "\n" + _u8L("UPLOADED") + "\n" + m_status_message;
} else {
m_text1 = line1 + "\n" + m_original_host;
}
} else {
// whole text is no longer than 2 lines, filename is max 1 line long.
std::string rest = "" + (m_original_host == m_host ? m_host : m_host + " (" + m_original_host + ")");
std::string line1;
if (ImGui::CalcTextSize(m_filename.c_str()).x > m_window_width - m_window_width_offset) {
line1 = shorten_to_line(m_filename, "");
} else {
line1 = shorten_to_line(m_filename + rest, {});
size_t over = line1.size() - m_filename.size();
if (over < 0)
over = 0;
if (over < rest.size())
rest = rest.substr(over);
else if (over >= rest.size())
rest.clear();
}
std::string line2 = shorten_to_line(rest, "");
// ... if in total that makes more than 1 line, whole notification will behave as 3 line notification (as base height)
if (ImGui::CalcTextSize((line1 + line2).c_str()).x > m_window_width - m_window_width_offset)
m_normal_lines_count = 3;
else
m_normal_lines_count = 2;
if (m_uj_state == UploadJobState::PB_COMPLETED || m_uj_state == UploadJobState::PB_COMPLETED_WITH_WARNING)
m_text1 = line1 + line2 + "\n" + _u8L("COMPLETED") + "\n" + m_status_message;
else
m_text1 = line1 + line2;
// ... if in total that makes more than 1 line, whole notification will behave as 3 line notification (as base height)
if (ImGui::CalcTextSize((line1 + line2).c_str()).x > m_window_width - m_window_width_offset)
m_normal_lines_count = 3;
else
m_normal_lines_count = 2;
if (m_uj_state == UploadJobState::PB_COMPLETED || m_uj_state == UploadJobState::PB_COMPLETED_WITH_WARNING)
m_text1 = line1 + line2 + "\n" + _u8L("UPLOADED") + "\n" + m_status_message;
else
m_text1 = line1 + line2;
}
}
void NotificationManager::PrintHostUploadNotification::set_percentage(float percent)
@ -1404,6 +1418,12 @@ void NotificationManager::PrintHostUploadNotification::set_percentage(float perc
}
}
bool NotificationManager::PrintHostUploadNotification::on_text_click() {
if (m_callback_override != nullptr)
return m_callback_override(m_evt_handler);
return false;
}
void NotificationManager::PrintHostUploadNotification::complete()
{
m_uj_state = UploadJobState::PB_COMPLETED;
@ -1424,7 +1444,6 @@ void NotificationManager::PrintHostUploadNotification::render_text(const float w
// If completed, whole text is part of m_text_1 and is rendered by PopNotification function.
if (m_uj_state != UploadJobState::PB_COMPLETED && m_uj_state != UploadJobState::PB_COMPLETED_WITH_WARNING) {
// hypertext is not rendered at all. If it is needed, it needs to be added here.
// m_endlines should have endline for each line and then for hypertext thus m_endlines[1] should always be in m_text1
if (m_endlines[0] != m_endlines[1]) {
assert(m_text1.size() >= m_endlines[0] || m_text1.size() >= m_endlines[1]);
@ -1434,13 +1453,15 @@ void NotificationManager::PrintHostUploadNotification::render_text(const float w
ImGui::SetCursorPosX(m_left_indentation);
ImGui::SetCursorPosY(m_line_height / 4);
ImGuiPureWrap::text(m_text1.substr(0, m_endlines[0]).c_str());
ImGui::SetCursorPosX(m_left_indentation);
ImGui::SetCursorPosY(m_line_height + m_line_height / 4);
std::string line = m_text1.substr(m_endlines[0] + (m_text1[m_endlines[0]] == '\n' || m_text1[m_endlines[0]] == ' ' ? 1 : 0), m_endlines[1] - m_endlines[0] - (m_text1[m_endlines[0]] == '\n' || m_text1[m_endlines[0]] == ' ' ? 1 : 0));
ImGuiPureWrap::text(line.c_str());
// uncomment only if close and stop button should be next to each other
//if (m_has_cancel_button)
// render_cancel_button(win_size_x, win_size_y, win_pos_x, win_pos_y);
std::string line = m_text1.substr(m_endlines[0] + (m_text1[m_endlines[0]] == '\n' || m_text1[m_endlines[0]] == ' ' ? 1 : 0), m_endlines[1] - m_endlines[0] - (m_text1[m_endlines[0]] == '\n' || m_text1[m_endlines[0]] == ' ' ? 1 : 0));
// if there is a hypertext, it is whole second line
if (m_hypertext_override) {
render_hypertext(m_left_indentation, m_line_height + m_line_height / 4, line);
} else {
ImGui::SetCursorPosX(m_left_indentation);
ImGui::SetCursorPosY(m_line_height + m_line_height / 4);
ImGuiPureWrap::text(line.c_str());
}
render_bar(win_size_x, win_size_y, win_pos_x, win_pos_y);
}
else {
@ -1455,8 +1476,9 @@ void NotificationManager::PrintHostUploadNotification::render_text(const float w
render_cancel_button(win_size_x, win_size_y, win_pos_x, win_pos_y);
render_bar(win_size_x, win_size_y, win_pos_x, win_pos_y);
}
} else
PopNotification::render_text(win_size_x, win_size_y, win_pos_x, win_pos_y);
} else {
PopNotification::render_text(win_size_x, win_size_y, win_pos_x, win_pos_y);
}
}
void NotificationManager::PrintHostUploadNotification::render_bar(const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y)
{
@ -1490,8 +1512,7 @@ void NotificationManager::PrintHostUploadNotification::render_bar(const float wi
break;
case Slic3r::GUI::NotificationManager::PrintHostUploadNotification::UploadJobState::PB_COMPLETED:
case Slic3r::GUI::NotificationManager::PrintHostUploadNotification::UploadJobState::PB_COMPLETED_WITH_WARNING:
// whole text with both "COMPLETED" and status message is generated in generate_text()
break;
break;
}
ImGuiPureWrap::text(text.c_str());
@ -2386,6 +2407,20 @@ void NotificationManager::set_upload_job_notification_completed_with_warning(int
}
}
void NotificationManager::set_upload_job_notification_hypertext(int id, std::function<bool(wxEvtHandler*)> callback)
{
for (std::unique_ptr<PopNotification>& notification : m_pop_notifications) {
if (notification->get_type() == NotificationType::PrintHostUpload) {
PrintHostUploadNotification* phun = dynamic_cast<PrintHostUploadNotification*>(notification.get());
if (phun->compare_job_id(id)) {
phun->set_hypertext_override(callback);
wxGetApp().plater()->get_current_canvas3D()->schedule_extra_frame(0);
break;
}
}
}
}
void NotificationManager::upload_job_notification_show_canceled(int id, const std::string& filename, const std::string& host)
{
for (std::unique_ptr<PopNotification>& notification : m_pop_notifications) {

View File

@ -236,6 +236,7 @@ public:
void set_upload_job_notification_comp_on_100(int id, bool comp);
void set_upload_job_notification_completed(int id);
void set_upload_job_notification_completed_with_warning(int id);
void set_upload_job_notification_hypertext(int i, std::function<bool(wxEvtHandler*)> callback);
void upload_job_notification_show_canceled(int id, const std::string& filename, const std::string& host);
void upload_job_notification_show_error(int id, const std::string& filename, const std::string& host);
// Download App progress
@ -601,6 +602,7 @@ private:
set_percentage(percentage);
}
void set_percentage(float percent) override;
bool on_text_click() override;
void cancel() { m_uj_state = UploadJobState::PB_CANCELLED; m_has_cancel_button = false; }
void error() { m_uj_state = UploadJobState::PB_ERROR; m_has_cancel_button = false; init(); }
bool compare_job_id(const int other_id) const { return m_job_id == other_id; }
@ -611,6 +613,12 @@ private:
void set_complete_on_100(bool val) { m_complete_on_100 = val; }
void complete();
void complete_with_warning();
void set_hypertext_override(std::function<bool(wxEvtHandler *)> callback)
{
m_hypertext_override = true;
m_callback_override = callback;
init();
}
protected:
void init() override;
void count_spaces() override;
@ -643,6 +651,9 @@ private:
bool m_more_hypertext_used { false };
// When m_complete_on_100 is set to false - percent >= 1 wont switch to PB_COMPLETED state.
bool m_complete_on_100 { true };
bool m_hypertext_override { false };
std::function<bool(wxEvtHandler *)> m_callback_override;
};
class SlicingProgressNotification : public ProgressBarNotification

View File

@ -6074,9 +6074,9 @@ void Plater::connect_gcode()
*/
const Preset* selected_printer_preset = &wxGetApp().preset_bundle->printers.get_selected_preset();
boost::property_tree::ptree ptree;
boost::property_tree::ptree ptree;
const std::string filename = UserAccountUtils::get_keyword_from_json(ptree, dialog_msg, "filename");
const std::string team_id = UserAccountUtils::get_keyword_from_json(ptree, dialog_msg, "team_id");
const std::string team_id = UserAccountUtils::get_keyword_from_json(ptree, dialog_msg, "team_id");
std::string data_subtree = UserAccountUtils::get_print_data_from_json(dialog_msg, "data");
if (filename.empty() || team_id.empty() || data_subtree.empty()) {
@ -6101,7 +6101,6 @@ void Plater::connect_gcode()
upload_job.upload_data.upload_path = boost::filesystem::path(filename);
p->export_gcode(fs::path(), false, std::move(upload_job));
}
void Plater::send_gcode()

View File

@ -387,7 +387,7 @@ void PrintHostQueueDialog::append_job(const PrintHostJob &job)
// Both strings are UTF-8 encoded.
upload_names.emplace_back(job.printhost->get_host(), job.upload_data.upload_path.string());
wxGetApp().notification_manager()->push_upload_job_notification(job_list->GetItemCount(), (float)size_i / 1024 / 1024, job.upload_data.upload_path.string(), job.printhost->get_host());
wxGetApp().notification_manager()->push_upload_job_notification(job_list->GetItemCount(), (float)size_i / 1024 / 1024, job.upload_data.upload_path.string(), job.printhost->get_notification_host());
}
void PrintHostQueueDialog::on_dpi_changed(const wxRect &suggested_rect)
@ -528,6 +528,13 @@ void PrintHostQueueDialog::on_info(Event& evt)
wxGetApp().notification_manager()->set_upload_job_notification_status(evt.job_id + 1, into_u8(evt.status));
} else if (evt.tag == L"set_complete_off") {
wxGetApp().notification_manager()->set_upload_job_notification_comp_on_100(evt.job_id + 1, false);
} else if (evt.tag == L"prusaconnect_printer_address") {
wxGetApp().notification_manager()->set_upload_job_notification_hypertext(evt.job_id + 1
, [evt](wxEvtHandler *) {
wxGetApp().mainframe->show_connect_tab(into_u8(evt.status));
return false ;
}
);
}
}

View File

@ -203,7 +203,12 @@ void WebViewPanel::on_idle(wxIdleEvent& WXUNUSED(evt))
if (m_shown && m_load_error_page) {
m_load_error_page = false;
load_url(GUI::format_wxstr("file://%1%/web/connection_failed.html", boost::filesystem::path(resources_dir()).generic_string()));
if (m_load_default_url_on_next_error) {
m_load_default_url_on_next_error = false;
load_url(m_default_url);
} else {
load_url(GUI::format_wxstr("file://%1%/web/connection_failed.html", boost::filesystem::path(resources_dir()).generic_string()));
}
}
}
#ifdef DEBUG_URL_PANEL
@ -783,6 +788,9 @@ void ConnectWebViewPanel::on_script_message(wxWebViewEvent& evt)
}
void ConnectWebViewPanel::on_navigation_request(wxWebViewEvent &evt)
{
#ifdef DEBUG_URL_PANEL
m_url->SetValue(evt.GetURL());
#endif
BOOST_LOG_TRIVIAL(debug) << "Navigation requested to: " << into_u8(evt.GetURL());
if (evt.GetURL() == m_default_url) {
m_reached_default_url = true;

View File

@ -62,12 +62,13 @@ public:
void set_default_url(const wxString& url) { m_default_url = url; }
virtual void sys_color_changed();
void set_load_default_url_on_next_error(bool val) { m_load_default_url_on_next_error = val; }
protected:
virtual void on_page_will_load();
protected:
wxWebView* m_browser { nullptr };
bool m_load_default_url { false };
#ifdef DEBUG_URL_PANEL
@ -100,6 +101,7 @@ protected:
bool m_load_error_page { false };
bool m_shown { false };
bool m_load_default_url_on_next_error { false };
std::vector<std::string> m_script_message_hadler_names;
};

View File

@ -66,6 +66,7 @@ public:
// A print host usually does not support multiple printers, with the exception of Repetier server.
virtual bool supports_multiple_printers() const { return false; }
virtual std::string get_host() const = 0;
virtual std::string get_notification_host() const {return get_host(); }
// Support for Repetier server multiple groups & printers. Not supported by other print hosts.
// Returns false if not supported. May throw HostNetworkError.

View File

@ -6,6 +6,8 @@
#include "slic3r/GUI/GUI_App.hpp"
#include "slic3r/GUI/Plater.hpp"
#include "slic3r/GUI/UserAccount.hpp"
#include "slic3r/GUI/UserAccountUtils.hpp"
#include <boost/log/trivial.hpp>
#include <boost/nowide/convert.hpp>
@ -153,6 +155,12 @@ bool PrusaConnectNew::init_upload(PrintHostUpload upload_data, std::string& out)
bool PrusaConnectNew::upload(PrintHostUpload upload_data, ProgressFn progress_fn, ErrorFn error_fn, InfoFn info_fn) const
{
std::string json = GUI::format(upload_data.data_json, "", "1");
boost::property_tree::ptree ptree;
const std::string printer_uuid = GUI::UserAccountUtils::get_keyword_from_json(ptree, json, "printer_uuid");
wxString printer_page_url = GUI::format("https://connect.prusa3d.com/printer/%1%/dashboard", printer_uuid);
info_fn(L"prusaconnect_printer_address", printer_page_url);
std::string init_out;
if (!init_upload(upload_data, init_out))
{
@ -197,6 +205,7 @@ bool PrusaConnectNew::upload(PrintHostUpload upload_data, ProgressFn progress_fn
, get_host(), m_team_id, upload_id/*, m_uuid, escaped_upload_path, set_ready, position, wait_until*/);
bool res = true;
BOOST_LOG_TRIVIAL(info) << boost::format("%1%: Uploading file %2% at %3%, filename: %4%, path: %5%, print: %6%")
% name
% upload_data.source_path
@ -230,6 +239,11 @@ bool PrusaConnectNew::upload(PrintHostUpload upload_data, ProgressFn progress_fn
return res;
}
std::string PrusaConnectNew::get_notification_host() const
{
return "Prusa Connect";
}
bool PrusaConnectNew::get_storage(wxArrayString& storage_path, wxArrayString& storage_name) const
{
const char* name = get_name();

View File

@ -34,6 +34,7 @@ public:
bool can_test() const override { return true; }
PrintHostPostUploadActions get_post_upload_actions() const override { return PrintHostPostUploadAction::StartPrint | PrintHostPostUploadAction::QueuePrint; }
std::string get_host() const override { return Utils::ServiceConfig::instance().connect_url(); }
std::string get_notification_host() const override;
bool get_storage(wxArrayString& storage_path, wxArrayString& storage_name) const override;
//const std::string& get_apikey() const { return m_apikey; }
//const std::string& get_cafile() const { return m_cafile; }