diff --git a/resources/web/other_connection_failed.html b/resources/web/other_connection_failed.html deleted file mode 100644 index 3ea607b3be..0000000000 --- a/resources/web/other_connection_failed.html +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - Connection failed - - - -
-

Connection failed

-

Something went wrong.

- -
- - diff --git a/resources/web/other_error.html b/resources/web/other_error.html new file mode 100644 index 0000000000..24b29d72d2 --- /dev/null +++ b/resources/web/other_error.html @@ -0,0 +1,70 @@ + + + + + + Connect-Slicer integration + + + +
+
+

+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+

Something went wrong.

+ +
+
+ + \ No newline at end of file diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index a938865bb9..a79d6dbc2f 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -4145,7 +4145,12 @@ void GUI_App::printables_slice_request(const std::string& download_url, const st } void GUI_App::printables_print_request(const std::string& download_url, const std::string& model_url) { + plater()->printables_to_connect_gcode(Utils::ServiceConfig::instance().printables_url() + model_url); +} +void GUI_App::printables_login_request() +{ + plater_->get_user_account()->do_login(); } void GUI_App::open_link_in_printables(const std::string& url) diff --git a/src/slic3r/GUI/GUI_App.hpp b/src/slic3r/GUI/GUI_App.hpp index cf3c30c287..a85c8a8480 100644 --- a/src/slic3r/GUI/GUI_App.hpp +++ b/src/slic3r/GUI/GUI_App.hpp @@ -439,6 +439,7 @@ public: void printables_download_request(const std::string& download_url, const std::string& model_url); void printables_slice_request(const std::string& download_url, const std::string& model_url); void printables_print_request(const std::string& download_url, const std::string& model_url); + void printables_login_request(); void open_link_in_printables(const std::string& url); private: bool on_init_inner(); diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index eca7401888..0f2bd93484 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -880,9 +880,12 @@ void MainFrame::show_printables_tab(const std::string& url) if (!m_printables_webview_added) { return; } - m_tabpanel->SetSelection(m_tabpanel->FindPage(m_printables_webview)); + // we have to set next url first, than show the tab + // printables_tab has to reload on show everytime + // so it is not possible load_url right after show m_printables_webview->set_load_default_url_on_next_error(true); - m_printables_webview->load_url_from_outside(url); + m_printables_webview->set_next_show_url(url); + m_tabpanel->SetSelection(m_tabpanel->FindPage(m_printables_webview)); } void MainFrame::add_printables_webview_tab() { diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 395f29dc8d..e22d7a260a 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -6017,6 +6017,18 @@ bool load_secret(const std::string& id, const std::string& opt, std::string& usr #endif // wxUSE_SECRETSTORE } } + + +void Plater::printables_to_connect_gcode(const std::string& url) +{ + { + PrintablesConnectUploadDialog dialog(this, url); + if (dialog.ShowModal() != wxID_OK) { + return; + } + } +} + void Plater::connect_gcode() { assert(p->user_account->is_logged()); diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index c492912d3a..e610e552d4 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -229,6 +229,7 @@ public: void send_gcode_inner(DynamicPrintConfig* physical_printer_config); void eject_drive(); void connect_gcode(); + void printables_to_connect_gcode(const std::string& url); std::string get_upload_filename(); void take_snapshot(const std::string &snapshot_name); diff --git a/src/slic3r/GUI/WebViewDialog.cpp b/src/slic3r/GUI/WebViewDialog.cpp index fe33241109..b77e298be2 100644 --- a/src/slic3r/GUI/WebViewDialog.cpp +++ b/src/slic3r/GUI/WebViewDialog.cpp @@ -630,6 +630,31 @@ void PrinterPickWebViewDialog::on_reload_event(const std::string& message_data) m_browser->LoadURL(m_default_url); } +PrintablesConnectUploadDialog::PrintablesConnectUploadDialog(wxWindow* parent, const std::string url) + : WebViewDialog(parent + , GUI::from_u8(url) + , _L("Choose a printer") + , wxSize(parent->GetClientSize().x / 4 * 3, parent->GetClientSize().y/ 5 * 4) + ,{"_prusaSlicer"} + , "connect_loading") +{ + SetMinSize(wxSize(std::max(parent->GetClientSize().x / 2, 100 * wxGetApp().em_unit()), std::max(parent->GetClientSize().y / 2, 70 * wxGetApp().em_unit()))); + Centre(); +} + +void PrintablesConnectUploadDialog::on_dpi_changed(const wxRect &suggested_rect) +{ + wxWindow *parent = GetParent(); + const wxSize &size = wxSize( + std::max(parent->GetClientSize().x / 2, 100 * wxGetApp().em_unit()), + std::max(parent->GetClientSize().y / 2, 70 * wxGetApp().em_unit()) + ); + SetMinSize(size); + Fit(); + Refresh(); +} + + LoginWebViewDialog::LoginWebViewDialog(wxWindow *parent, std::string &ret_val, const wxString& url, wxEvtHandler* evt_handler) : WebViewDialog(parent, url, _L("Log in dialog"), wxSize(50 * wxGetApp().em_unit(), 80 * wxGetApp().em_unit()), {}) diff --git a/src/slic3r/GUI/WebViewDialog.hpp b/src/slic3r/GUI/WebViewDialog.hpp index d9e890fc3f..78fdd35c74 100644 --- a/src/slic3r/GUI/WebViewDialog.hpp +++ b/src/slic3r/GUI/WebViewDialog.hpp @@ -109,6 +109,15 @@ private: std::string& m_ret_val; }; +class PrintablesConnectUploadDialog : public WebViewDialog +{ +public: + PrintablesConnectUploadDialog(wxWindow* parent, const std::string url); +protected: + void on_dpi_changed(const wxRect &suggested_rect) override; + +}; + class LoginWebViewDialog : public WebViewDialog { public: diff --git a/src/slic3r/GUI/WebViewPanel.cpp b/src/slic3r/GUI/WebViewPanel.cpp index 9ec5767ce4..acb0fcc67b 100644 --- a/src/slic3r/GUI/WebViewPanel.cpp +++ b/src/slic3r/GUI/WebViewPanel.cpp @@ -8,10 +8,10 @@ #include "slic3r/GUI/format.hpp" #include "slic3r/GUI/WebView.hpp" #include "slic3r/GUI/WebViewPlatformUtils.hpp" -#include "slic3r/Utils/ServiceConfig.hpp" - #include "slic3r/GUI/MsgDialog.hpp" #include "slic3r/GUI/Field.hpp" +#include "libslic3r/AppConfig.hpp" +#include "libslic3r/Config.hpp" #include // IWYU pragma: keep @@ -207,7 +207,7 @@ void WebViewPanel::on_idle(wxIdleEvent& WXUNUSED(evt)) m_load_error_page = false; if (m_load_default_url_on_next_error) { m_load_default_url_on_next_error = false; - load_url(m_default_url); + load_default_url(); } else { load_url(GUI::format_wxstr("file://%1%/web/%2%.html", boost::filesystem::path(resources_dir()).generic_string(), m_error_html)); } @@ -781,7 +781,7 @@ void ConnectWebViewPanel::on_connect_action_print(const std::string& message_dat } PrinterWebViewPanel::PrinterWebViewPanel(wxWindow* parent, const wxString& default_url) - : WebViewPanel(parent, default_url, {"ExternalApp"}, "other_loading_reload", "other_connection_failed") + : WebViewPanel(parent, default_url, {"ExternalApp"}, "other_loading_reload", "other_error") { if (!m_browser) return; @@ -857,7 +857,7 @@ void PrinterWebViewPanel::sys_color_changed() PrintablesWebViewPanel::PrintablesWebViewPanel(wxWindow* parent) - : WebViewPanel(parent, GUI::from_u8(Utils::ServiceConfig::instance().printables_url()), { "ExternalApp" }, "other_loading_reload", "other_connection_failed") + : WebViewPanel(parent, GUI::from_u8(Utils::ServiceConfig::instance().printables_url()), { "ExternalApp" }, "other_loading_reload", "other_error") { m_browser->Bind(wxEVT_WEBVIEW_LOADED, &PrintablesWebViewPanel::on_loaded, this); @@ -908,27 +908,6 @@ void PrintablesWebViewPanel::on_navigation_request(wxWebViewEvent &evt) } } -void PrintablesWebViewPanel::load_default_url() -{ - std::string actual_default_url = get_url_lang_theme(Utils::ServiceConfig::instance().printables_url() + "/homepage"); - const std::string access_token = wxGetApp().plater()->get_user_account()->get_access_token(); - - // in case of opening printables logged out - delete cookies and localstorage to get rid of last login - if (access_token.empty()) { - delete_cookies(m_browser, Utils::ServiceConfig::instance().printables_url()); - m_browser->AddUserScript("localStorage.clear();"); - load_url(actual_default_url); - return; - } - // add token to first request -#ifdef _WIN32 - add_request_authorization(m_browser, m_default_url, access_token); - load_url(GUI::from_u8(actual_default_url)); -#else - load_request(m_browser, actual_default_url, access_token); -#endif -} - void PrintablesWebViewPanel::on_loaded(wxWebViewEvent& evt) { #ifdef _WIN32 @@ -1000,20 +979,20 @@ void PrintablesWebViewPanel::on_show(wxShowEvent& evt) return; } // in case login changed, resend login / logout - // DK: it seems to me, it is safer to do login / logout (where logout means requesting the page again) + // DK1: it seems to me, it is safer to do login / logout (where logout means requesting the page again) // on every show of panel, // than to keep information if we have printables page in same state as slicer in terms of login // But im afraid it will be concidered not pretty... const std::string access_token = wxGetApp().plater()->get_user_account()->get_access_token(); if (access_token.empty()) { - logout(); + logout(m_next_show_url); } else { - login(access_token); + login(access_token, m_next_show_url); } - + m_next_show_url.clear(); } -void PrintablesWebViewPanel::logout() +void PrintablesWebViewPanel::logout(const std::string& override_url/* = std::string()*/) { if (!m_shown) { return; @@ -1021,15 +1000,18 @@ void PrintablesWebViewPanel::logout() delete_cookies(m_browser, Utils::ServiceConfig::instance().printables_url()); m_browser->RunScript("localStorage.clear();"); + std::string next_url = override_url.empty() + ? get_url_lang_theme(m_browser->GetCurrentURL()) + : get_url_lang_theme(from_u8(override_url)); #ifdef _WIN32 - load_url(GUI::from_u8(get_url_lang_theme(m_browser->GetCurrentURL()))); + load_url(GUI::from_u8(next_url)); #else // We cannot do simple reload here, it would keep the access token in the header - load_request(m_browser, get_url_lang_theme(m_browser->GetCurrentURL()), std::string()); + load_request(m_browser, next_url, std::string()); #endif // } -void PrintablesWebViewPanel::login(const std::string& access_token) +void PrintablesWebViewPanel::login(const std::string& access_token, const std::string& override_url/* = std::string()*/) { if (!m_shown) { return; @@ -1048,8 +1030,34 @@ void PrintablesWebViewPanel::login(const std::string& access_token) , access_token); run_script(script); - run_script("window.location.reload();"); + if ( override_url.empty()) { + run_script("window.location.reload();"); + } else { + load_url(GUI::from_u8(get_url_lang_theme(from_u8(override_url)))); + } } + +void PrintablesWebViewPanel::load_default_url() +{ + std::string actual_default_url = get_url_lang_theme(from_u8(Utils::ServiceConfig::instance().printables_url() + "/homepage")); + const std::string access_token = wxGetApp().plater()->get_user_account()->get_access_token(); + + // in case of opening printables logged out - delete cookies and localstorage to get rid of last login + if (access_token.empty()) { + delete_cookies(m_browser, Utils::ServiceConfig::instance().printables_url()); + m_browser->AddUserScript("localStorage.clear();"); + load_url(actual_default_url); + return; + } + // add token to first request +#ifdef _WIN32 + add_request_authorization(m_browser, m_default_url, access_token); + load_url(GUI::from_u8(actual_default_url)); +#else + load_request(m_browser, actual_default_url, access_token); +#endif +} + void PrintablesWebViewPanel::send_refreshed_token(const std::string& access_token) { if (m_load_default_url) { @@ -1071,11 +1079,6 @@ void PrintablesWebViewPanel::send_will_refresh() run_script(script); } -void PrintablesWebViewPanel::load_url_from_outside(const std::string& url) -{ - load_url(from_u8(Utils::ServiceConfig::instance().printables_url() + url)); -} - void PrintablesWebViewPanel::on_script_message(wxWebViewEvent& evt) { BOOST_LOG_TRIVIAL(error) << "received message from Printables: " << evt.GetString(); @@ -1106,11 +1109,31 @@ void PrintablesWebViewPanel::on_reload_event(const std::string& message_data) void PrintablesWebViewPanel::on_printables_event_print_gcode(const std::string& message_data) { BOOST_LOG_TRIVIAL(error) << __FUNCTION__<< " " << message_data; + + // { "event": "downloadFile", "url": "https://media.printables.com/somesecure.stl", "modelUrl": "https://www.printables.com/model/123" } + std::string download_url; + std::string model_url; + try { + std::stringstream ss(message_data); + pt::ptree ptree; + pt::read_json(ss, ptree); + if (const auto url = ptree.get_optional("url"); url) { + download_url = *url; + } + if (const auto url = ptree.get_optional("modelUrl"); url) { + model_url = *url; + } + } catch (const std::exception &e) { + BOOST_LOG_TRIVIAL(error) << "Could not parse printables message. " << e.what(); + return; + } + assert(!download_url.empty() && !model_url.empty()); + wxGetApp().printables_print_request(download_url, model_url); } void PrintablesWebViewPanel::on_printables_event_download_file(const std::string& message_data) { - BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << " " << message_data; - // { "event": "downloadFile", "url": "https://media.printables.com/somesecure.stl", "modelUrl": "https://www.printables.com/model/123" } + BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << " " << message_data; + // { "event": "printGcode", "url": "https://media.printables.com/somesecure.gcode", "modelUrl": "https://www.printables.com/model/123" } std::string download_url; std::string model_url; try { @@ -1130,11 +1153,11 @@ void PrintablesWebViewPanel::on_printables_event_download_file(const std::string assert(!download_url.empty() && !model_url.empty()); boost::filesystem::path url_path(download_url); show_download_notification(url_path.filename().string()); - wxGetApp().printables_download_request(download_url, model_url); + wxGetApp().printables_download_request(download_url, model_url); } void PrintablesWebViewPanel::on_printables_event_slice_file(const std::string& message_data) { - BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << " " << message_data; + BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << " " << message_data; // { "event": "sliceFile", "url": "https://media.printables.com/somesecure.zip", "modelUrl": "https://www.printables.com/model/123" } std::string download_url; std::string model_url; @@ -1158,12 +1181,14 @@ void PrintablesWebViewPanel::on_printables_event_slice_file(const std::string& m void PrintablesWebViewPanel::on_printables_event_required_login(const std::string& message_data) { - BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << " " << message_data; + BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << " " << message_data; + wxGetApp().printables_login_request(); } void PrintablesWebViewPanel::show_download_notification(const std::string& filename) { - std::string message = GUI::format(_u8L("Downloading %1%"),filename); + std::string message_filename = GUI::format(_u8L("Downloading %1%"),filename); + std::string message_dest = GUI::format(_u8L("To %1%"), escape_string_cstyle(wxGetApp().app_config->get("url_downloader_dest"))); std::string script = GUI::format(R"( // Inject custom CSS var style = document.createElement('style'); @@ -1185,10 +1210,19 @@ void PrintablesWebViewPanel::show_download_notification(const std::string& filen justify-content: space-between; align-items: center; box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.3); /* Add a subtle shadow */ - min-width: 350px; /* Ensure it has a minimum width */ + min-width: 350px; + max-width: 350px; min-height: 50px; } - + .notification-popup div { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + padding-right: 20px; /* Add padding to make text truncate earlier */ + } + .notification-popup b { + color: #ffa500; + } .notification-popup a:hover { text-decoration: underline; /* Underline on hover */ } @@ -1223,6 +1257,7 @@ void PrintablesWebViewPanel::show_download_notification(const std::string& filen notifDiv.innerHTML = `
PrusaSlicer: %1% +
%2%
`; notifDiv.className = 'notification-popup'; @@ -1239,7 +1274,7 @@ void PrintablesWebViewPanel::show_download_notification(const std::string& filen } appendNotification(); -)", message); +)", message_filename, message_dest); run_script(script); } diff --git a/src/slic3r/GUI/WebViewPanel.hpp b/src/slic3r/GUI/WebViewPanel.hpp index be9e181f22..d5d276cb62 100644 --- a/src/slic3r/GUI/WebViewPanel.hpp +++ b/src/slic3r/GUI/WebViewPanel.hpp @@ -8,6 +8,7 @@ #include "GUI_Utils.hpp" #include "UserAccountSession.hpp" #include "ConnectRequestHandler.hpp" +#include "slic3r/Utils/ServiceConfig.hpp" #ifdef DEBUG_URL_PANEL #include @@ -179,11 +180,11 @@ public: void on_script_message(wxWebViewEvent& evt) override; void sys_color_changed() override; - void logout(); - void login(const std::string& access_token); + void logout(const std::string& override_url = std::string()); + void login(const std::string& access_token, const std::string& override_url = std::string()); void send_refreshed_token(const std::string& access_token); void send_will_refresh(); - void load_url_from_outside(const std::string& url); + void set_next_show_url(const std::string& url) {m_next_show_url = Utils::ServiceConfig::instance().printables_url() + url; } private: void handle_message(const std::string& message); void on_printables_event_access_token_expired(const std::string& message_data); @@ -197,7 +198,7 @@ private: void show_download_notification(const std::string& filename); std::map> m_events; - + std::string m_next_show_url; /* Eventy Slicer -> Printables accessTokenWillChange diff --git a/src/slic3r/GUI/format.hpp b/src/slic3r/GUI/format.hpp index e80017174d..9c80907ee0 100644 --- a/src/slic3r/GUI/format.hpp +++ b/src/slic3r/GUI/format.hpp @@ -12,6 +12,7 @@ // This wrapper also manages implicit conversion from wxString to UTF8 and format_wxstr() variants are provided to format into wxString. #include +#include namespace Slic3r::internal::format { // Wrapper around wxScopedCharBuffer to indicate that the content is UTF8 formatted.