SPE-2535: Improvments of Printables events

Missing include

Printables event Require login

Improved error page

Prepare opening Printables to Connect upload dialog

debug fix

Another debug fix

prevent reload on load request

Load new url already in on_show

Improved javascript notification
This commit is contained in:
David Kocik 2024-10-28 10:39:58 +01:00 committed by Lukas Matena
parent 93b0adf964
commit da49e8edfb
12 changed files with 218 additions and 83 deletions

View File

@ -1,28 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Connection failed</title>
<style>
body {
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
margin: 0;
}
.container {
text-align: center;
}
</style>
</head>
<body>
<div class="container">
<h1>Connection failed</h1>
<p>Something went wrong.</p>
<button style="margin-top: 20px; padding: 10px 20px; font-size: 16px;" onclick="window.ExternalApp.postMessage(JSON.stringify({ event: 'reloadHomePage' }))">Reload</button>
</div>
</body>
</html>

View File

@ -0,0 +1,70 @@
<!doctype html>
<html lang='en'>
<head>
<meta charset='UTF-8' />
<meta content='width=device-width, initial-scale=1.0' name='viewport' />
<title>Connect-Slicer integration</title>
</head>
<body>
<!-- This page is not served anywhere, only to be copy 'n' pasted into Slicer as a fallback loading screen. -->
<div id='loading-screen' style='width: 100%; height: 100%'>
<div style='position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); text-align: center'>
<p>
<svg style='width: 80px'
viewBox='-250 -250 500 500' xmlns='http://www.w3.org/2000/svg'>
<style type='text/css'>
.filament {
stroke: #FA6831;
}
.spool {
stroke: #231F20;
fill: none;
}
.filament line {
stroke-linecap: round;
}
</style>
<defs>
<pattern class='spool' height='100' id='hexagon' patternTransform='scale(0.875)' patternUnits='userSpaceOnUse'
viewBox='-0.866025 -1.5 1.73205 3'
width='57.735'
>
<polygon fill='none' points='0,1 0.866025,0.5 0.866025,-0.5 0,-1 -0.866025,-0.5 -0.866025,0.5'
stroke-width='0.34' />
<line stroke-width='0.34' x1='0' x2='0' y1='1' y2='1.5'></line>
<line stroke-width='0.34' x1='0' x2='0' y1='-1' y2='-1.5'></line>
</pattern>
</defs>
<g class='filament'>
<circle fill='none' r='145' stroke-width='130'>
<!-- <animate attributeName='r' dur='6s' repeatCount='indefinite' values='145;80;145' />-->
<!-- <animate attributeName='stroke-width' dur='6s' repeatCount='indefinite' values='130;0;130' />-->
</circle>
<line stroke-width='12' x1='204' x2='204' y1='0' y2='245'>
<!-- <animate attributeName='x1' dur='6s' repeatCount='indefinite' values='204;74;204' />-->
<!-- <animate attributeName='x2' dur='6s' repeatCount='indefinite' values='204;74;204' />-->
</line>
</g>
<g class='spool'>
<circle fill='none' r='157' stroke='url(#hexagon)' stroke-width='171' />
<circle r='244' stroke-width='12' />
<circle r='71' stroke-width='18' />
<!-- <animateTransform
attributeName='transform' begin='0s'
dur='6s'
fill='freeze'
repeatCount='indefinite'
type='rotate'
values='0;540;0'
/>-->
</g>
</svg>
</p>
<p style="font-size: 24px;">Something went wrong.</p>
<button style="margin-top: 20px; padding: 10px 20px; font-size: 16px;" onclick="window.ExternalApp.postMessage(JSON.stringify({ event: 'reloadHomePage' }))">Reload</button>
</div>
</div>
</body>
</html>

View File

@ -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)

View File

@ -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();

View File

@ -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()
{

View File

@ -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());

View File

@ -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);

View File

@ -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()), {})

View File

@ -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:

View File

@ -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 <libslic3r/PresetBundle.hpp> // 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<std::string>("url"); url) {
download_url = *url;
}
if (const auto url = ptree.get_optional<std::string>("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 = `
<div>
<b>PrusaSlicer: </b>%1%
<br>%2%
</div>
`;
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);
}

View File

@ -8,6 +8,7 @@
#include "GUI_Utils.hpp"
#include "UserAccountSession.hpp"
#include "ConnectRequestHandler.hpp"
#include "slic3r/Utils/ServiceConfig.hpp"
#ifdef DEBUG_URL_PANEL
#include <wx/infobar.h>
@ -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<std::string, std::function<void(const std::string&)>> m_events;
std::string m_next_show_url;
/*
Eventy Slicer -> Printables
accessTokenWillChange

View File

@ -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 <wx/string.h>
#include <ostream>
namespace Slic3r::internal::format {
// Wrapper around wxScopedCharBuffer to indicate that the content is UTF8 formatted.