From 697d945ca1e6f9a3817aeae63deb4e310e2d991a Mon Sep 17 00:00:00 2001 From: "lane.wei" Date: Thu, 22 Dec 2022 14:40:34 +0800 Subject: [PATCH] ENH: add the logic to prompt user to update network plugins Change-Id: I73cce20e58783a365ad2665c8e095dcf2e9c02ea --- src/slic3r/GUI/GUI_App.cpp | 6 + src/slic3r/GUI/NotificationManager.hpp | 12 ++ src/slic3r/GUI/Plater.cpp | 26 ++++ src/slic3r/GUI/Plater.hpp | 1 + src/slic3r/GUI/ReleaseNote.cpp | 170 +++++++++++++++++++++++-- src/slic3r/GUI/ReleaseNote.hpp | 14 ++ src/slic3r/Utils/PresetUpdater.cpp | 78 +++++++++++- 7 files changed, 289 insertions(+), 18 deletions(-) diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 8777eb064..9f46f4bc7 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -2495,11 +2495,14 @@ bool GUI_App::on_init_inner() void GUI_App::copy_network_if_available() { + if (app_config->get("update_network_plugin") != "true") + return; std::string network_library, player_library, network_library_dst, player_library_dst; std::string data_dir_str = data_dir(); boost::filesystem::path data_dir_path(data_dir_str); auto plugin_folder = data_dir_path / "plugins"; auto cache_folder = data_dir_path / "ota"; + std::string changelog_file = cache_folder.string() + "/network_plugins.json"; #if defined(_MSC_VER) || defined(_WIN32) network_library = cache_folder.string() + "/bambu_networking.dll"; player_library = cache_folder.string() + "/BambuSource.dll"; @@ -2548,6 +2551,9 @@ void GUI_App::copy_network_if_available() fs::remove(player_library); BOOST_LOG_TRIVIAL(info) << __FUNCTION__<< ": Copying player library from" << player_library << " to " << player_library_dst<<" successfully."; } + if (boost::filesystem::exists(changelog_file)) + fs::remove(changelog_file); + app_config->set("update_network_plugin", "false"); } bool GUI_App::on_init_network(bool try_backup) diff --git a/src/slic3r/GUI/NotificationManager.hpp b/src/slic3r/GUI/NotificationManager.hpp index b71f487d2..abf83fd58 100644 --- a/src/slic3r/GUI/NotificationManager.hpp +++ b/src/slic3r/GUI/NotificationManager.hpp @@ -135,6 +135,7 @@ enum class NotificationType BBLSeqPrintInfo, //BBL: plugin install hint BBLPluginInstallHint, + BBLPluginUpdateAvailable, BBLPreviewOnlyMode, }; @@ -873,6 +874,17 @@ private: _u8L("Integration failed.") }, NotificationData{NotificationType::UndoDesktopIntegrationSuccess, NotificationLevel::RegularNotificationLevel, 10, _u8L("Undo integration was successful.") }, + + NotificationData{NotificationType::BBLPluginUpdateAvailable, NotificationLevel::ImportantNotificationLevel, BBL_NOTICE_MAX_INTERVAL, + _L("New network plug-in available.").ToStdString(), + _L("Details").ToStdString(), + [](wxEvtHandler* evnthndlr) { + //BBS set feishu release page by default + wxCommandEvent* evt = new wxCommandEvent(EVT_UPDATE_PLUGINS_WHEN_LAUNCH); + wxQueueEvent(wxGetApp().plater(), evt); + return true; + }}, + NotificationData{NotificationType::UndoDesktopIntegrationFail, NotificationLevel::WarningNotificationLevel, 10, _u8L("Undo integration failed.") }, NotificationData{NotificationType::ExportOngoing, NotificationLevel::RegularNotificationLevel, 0, _u8L("Exporting.")}, diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 6ae4c87f8..ff480beb7 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -160,6 +160,7 @@ wxDEFINE_EVENT(EVT_PUBLISH_FINISHED, wxCommandEvent); wxDEFINE_EVENT(EVT_REPAIR_MODEL, wxCommandEvent); wxDEFINE_EVENT(EVT_FILAMENT_COLOR_CHANGED, wxCommandEvent); wxDEFINE_EVENT(EVT_INSTALL_PLUGIN_NETWORKING, wxCommandEvent); +wxDEFINE_EVENT(EVT_UPDATE_PLUGINS_WHEN_LAUNCH, wxCommandEvent); wxDEFINE_EVENT(EVT_INSTALL_PLUGIN_HINT, wxCommandEvent); wxDEFINE_EVENT(EVT_PREVIEW_ONLY_MODE_HINT, wxCommandEvent); //BBS: change light/dark mode @@ -2116,6 +2117,7 @@ private: void update_after_undo_redo(const UndoRedo::Snapshot& snapshot, bool temp_snapshot_was_taken = false); void on_action_export_to_sdcard(SimpleEvent&); void on_action_export_to_sdcard_all(SimpleEvent&); + void update_plugin_when_launch(wxCommandEvent& event); // path to project folder stored with no extension boost::filesystem::path m_project_folder; @@ -2210,6 +2212,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) this->q->Bind(EVT_FILAMENT_COLOR_CHANGED, &priv::on_filament_color_changed, this); this->q->Bind(EVT_INSTALL_PLUGIN_NETWORKING, &priv::install_network_plugin, this); this->q->Bind(EVT_INSTALL_PLUGIN_HINT, &priv::show_install_plugin_hint, this); + this->q->Bind(EVT_UPDATE_PLUGINS_WHEN_LAUNCH, &priv::update_plugin_when_launch, this); this->q->Bind(EVT_PREVIEW_ONLY_MODE_HINT, &priv::show_preview_only_hint, this); this->q->Bind(EVT_GLCANVAS_COLOR_MODE_CHANGED, &priv::on_change_color_mode, this); this->q->Bind(wxEVT_SYS_COLOUR_CHANGED, &priv::on_apple_change_color_mode, this); @@ -6185,6 +6188,29 @@ void Plater::priv::install_network_plugin(wxCommandEvent &event) return; } +void Plater::priv::update_plugin_when_launch(wxCommandEvent &event) +{ + std::string data_dir_str = data_dir(); + boost::filesystem::path data_dir_path(data_dir_str); + auto cache_folder = data_dir_path / "ota"; + std::string changelog_file = cache_folder.string() + "/network_plugins.json"; + + UpdatePluginDialog dlg(wxGetApp().mainframe); + dlg.update_info(changelog_file); + auto result = dlg.ShowModal(); + + auto app_config = wxGetApp().app_config; + if (!app_config) return; + + if (result == wxID_OK) { + app_config->set("update_network_plugin", "true"); + } + else if (result == wxID_NO) { + app_config->set("update_network_plugin", "false"); + } + app_config->save(); +} + void Plater::priv::show_install_plugin_hint(wxCommandEvent &event) { notification_manager->bbl_show_plugin_install_notification(into_u8(_L("Network Plug-in is not detected. Network related features are unavailable."))); diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index 9402b8877..1b930a0fd 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -87,6 +87,7 @@ wxDECLARE_EVENT(EVT_REPAIR_MODEL, wxCommandEvent); wxDECLARE_EVENT(EVT_FILAMENT_COLOR_CHANGED, wxCommandEvent); wxDECLARE_EVENT(EVT_INSTALL_PLUGIN_NETWORKING, wxCommandEvent); wxDECLARE_EVENT(EVT_INSTALL_PLUGIN_HINT, wxCommandEvent); +wxDECLARE_EVENT(EVT_UPDATE_PLUGINS_WHEN_LAUNCH, wxCommandEvent); wxDECLARE_EVENT(EVT_PREVIEW_ONLY_MODE_HINT, wxCommandEvent); wxDECLARE_EVENT(EVT_GLCANVAS_COLOR_MODE_CHANGED, SimpleEvent); diff --git a/src/slic3r/GUI/ReleaseNote.cpp b/src/slic3r/GUI/ReleaseNote.cpp index fca89f4f2..446aea37c 100644 --- a/src/slic3r/GUI/ReleaseNote.cpp +++ b/src/slic3r/GUI/ReleaseNote.cpp @@ -44,7 +44,7 @@ ReleaseNoteDialog::ReleaseNoteDialog(Plater *plater /*= nullptr*/) m_sizer_body->Add(0, 0, 0, wxLEFT, FromDIP(38)); - auto sm = create_scaled_bitmap("BambuStudio", nullptr, 70); + auto sm = create_scaled_bitmap("BambuStudio", nullptr, 70); auto brand = new wxStaticBitmap(this, wxID_ANY, sm, wxDefaultPosition, wxSize(FromDIP(70), FromDIP(70))); m_sizer_body->Add(brand, 0, wxALL, 0); @@ -85,8 +85,8 @@ void ReleaseNoteDialog::on_dpi_changed(const wxRect &suggested_rect) { } -void ReleaseNoteDialog::update_release_note(wxString release_note, std::string version) -{ +void ReleaseNoteDialog::update_release_note(wxString release_note, std::string version) +{ m_text_up_info->SetLabel(wxString::Format(_L("version %s update information :"), version)); wxBoxSizer * sizer_text_release_note = new wxBoxSizer(wxVERTICAL); auto m_staticText_release_note = new wxStaticText(m_vebview_release_note, wxID_ANY, release_note, wxDefaultPosition, wxDefaultSize, 0); @@ -97,6 +97,154 @@ void ReleaseNoteDialog::update_release_note(wxString release_note, std::string v m_vebview_release_note->Fit(); } +UpdatePluginDialog::UpdatePluginDialog(wxWindow* parent /*= nullptr*/) + : DPIDialog(static_cast(wxGetApp().mainframe), wxID_ANY, _L("Network plug-in update"), wxDefaultPosition, wxDefaultSize, wxCAPTION | wxCLOSE_BOX) +{ + std::string icon_path = (boost::format("%1%/images/BambuStudioTitle.ico") % resources_dir()).str(); + SetIcon(wxIcon(encode_path(icon_path.c_str()), wxBITMAP_TYPE_ICO)); + + SetBackgroundColour(*wxWHITE); + wxBoxSizer* m_sizer_main = new wxBoxSizer(wxVERTICAL); + auto m_line_top = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxSize(-1, 1)); + m_line_top->SetBackgroundColour(wxColour(166, 169, 170)); + m_sizer_main->Add(m_line_top, 0, wxEXPAND, 0); + m_sizer_main->Add(0, 0, 0, wxTOP, FromDIP(30)); + + wxBoxSizer* m_sizer_body = new wxBoxSizer(wxHORIZONTAL); + + + + auto sm = create_scaled_bitmap("BambuStudio", nullptr, 55); + auto brand = new wxStaticBitmap(this, wxID_ANY, sm, wxDefaultPosition, wxSize(FromDIP(55), FromDIP(55))); + + wxBoxSizer* m_sizer_right = new wxBoxSizer(wxVERTICAL); + + m_text_up_info = new wxStaticText(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0); + m_text_up_info->SetFont(::Label::Head_13); + m_text_up_info->SetMaxSize(wxSize(FromDIP(260), -1)); + m_text_up_info->Wrap(FromDIP(260)); + m_text_up_info->SetForegroundColour(wxColour(0x26, 0x2E, 0x30)); + + + operation_tips = new ::Label(this, _L("Click OK to update the Network plug-in when Bambu Studio launches next time.")); + operation_tips->SetFont(::Label::Body_12); + operation_tips->SetSize(wxSize(FromDIP(260), -1)); + operation_tips->Wrap(FromDIP(260)); + operation_tips->SetForegroundColour(*wxBLACK); + + + m_vebview_release_note = new wxScrolledWindow(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxVSCROLL); + m_vebview_release_note->SetScrollRate(5, 5); + m_vebview_release_note->SetBackgroundColour(wxColour(0xF8, 0xF8, 0xF8)); + m_vebview_release_note->SetMinSize(wxSize(FromDIP(260), FromDIP(150))); + m_vebview_release_note->SetMaxSize(wxSize(FromDIP(260), FromDIP(150))); + + auto sizer_button = new wxBoxSizer(wxHORIZONTAL); + + StateColor btn_bg_green(std::pair(wxColour(27, 136, 68), StateColor::Pressed), std::pair(wxColour(61, 203, 115), StateColor::Hovered), + std::pair(AMS_CONTROL_BRAND_COLOUR, StateColor::Normal)); + + StateColor btn_bg_white(std::pair(wxColour(206, 206, 206), StateColor::Pressed), std::pair(wxColour(238, 238, 238), StateColor::Hovered), + std::pair(*wxWHITE, StateColor::Normal)); + + auto m_button_ok = new Button(this, _L("OK")); + m_button_ok->SetBackgroundColor(btn_bg_green); + m_button_ok->SetBorderColor(*wxWHITE); + m_button_ok->SetTextColor(wxColour(0xFFFFFE)); + m_button_ok->SetFont(Label::Body_12); + m_button_ok->SetSize(wxSize(FromDIP(58), FromDIP(24))); + m_button_ok->SetMinSize(wxSize(FromDIP(58), FromDIP(24))); + m_button_ok->SetCornerRadius(FromDIP(12)); + + m_button_ok->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent& e) { + EndModal(wxID_OK); + }); + + auto m_button_cancel = new Button(this, _L("Cancel")); + m_button_cancel->SetBackgroundColor(btn_bg_white); + m_button_cancel->SetBorderColor(wxColour(38, 46, 48)); + m_button_cancel->SetFont(Label::Body_12); + m_button_cancel->SetSize(wxSize(FromDIP(58), FromDIP(24))); + m_button_cancel->SetMinSize(wxSize(FromDIP(58), FromDIP(24))); + m_button_cancel->SetCornerRadius(FromDIP(12)); + + m_button_cancel->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent& e) { + EndModal(wxID_NO); + }); + + sizer_button->AddStretchSpacer(); + sizer_button->Add(m_button_ok, 0, wxALL, FromDIP(5)); + sizer_button->Add(m_button_cancel, 0, wxALL, FromDIP(5)); + + m_sizer_right->Add(m_text_up_info, 0, 0, 0); + m_sizer_right->Add(0, 0, 0, wxTOP, FromDIP(5)); + m_sizer_right->Add(m_vebview_release_note, 0, wxEXPAND | wxRIGHT, FromDIP(20)); + m_sizer_right->Add(0, 0, 0, wxTOP, FromDIP(5)); + m_sizer_right->Add(operation_tips, 1, wxEXPAND | wxRIGHT, FromDIP(20)); + m_sizer_right->Add(0, 0, 0, wxTOP, FromDIP(5)); + m_sizer_right->Add(sizer_button, 0, wxEXPAND | wxRIGHT, FromDIP(20)); + + m_sizer_body->Add(0, 0, 0, wxLEFT, FromDIP(24)); + m_sizer_body->Add(brand, 0, wxALL, 0); + m_sizer_body->Add(0, 0, 0, wxRIGHT, FromDIP(20)); + m_sizer_body->Add(m_sizer_right, 1, wxBOTTOM | wxEXPAND, FromDIP(18)); + m_sizer_main->Add(m_sizer_body, 0, wxEXPAND, 0); + + SetSizer(m_sizer_main); + Layout(); + m_sizer_main->Fit(this); + + Centre(wxBOTH); + wxGetApp().UpdateDlgDarkUI(this); +} + +UpdatePluginDialog::~UpdatePluginDialog() {} + + +void UpdatePluginDialog::on_dpi_changed(const wxRect& suggested_rect) +{ +} + +void UpdatePluginDialog::update_info(std::string json_path) +{ + std::string version_str, description_str; + wxString version; + wxString description; + + try { + boost::nowide::ifstream ifs(json_path); + json j; + ifs >> j; + + version_str = j["version"]; + description_str = j["description"]; + } + catch(nlohmann::detail::parse_error &err) { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__<< ": parse "<SetMaxSize(wxSize(FromDIP(260), -1)); + m_text_up_info->Wrap(FromDIP(260)); + wxBoxSizer* sizer_text_release_note = new wxBoxSizer(wxVERTICAL); + auto m_text_label = new ::Label(m_vebview_release_note, description); + m_text_label->SetFont(::Label::Body_13); + m_text_label->SetForegroundColour(*wxBLACK); + m_text_label->SetMaxSize(wxSize(FromDIP(235), -1)); + m_text_label->Wrap(FromDIP(235)); + + sizer_text_release_note->Add(m_text_label, 0, wxALL, 5); + m_vebview_release_note->SetSizer(sizer_text_release_note); + m_vebview_release_note->Layout(); + m_vebview_release_note->Fit(); + Layout(); + Fit(); +} + void UpdateVersionDialog::alter_choice(wxCommandEvent& event) { wxGetApp().set_skip_version(m_remind_choice->GetValue()); @@ -174,7 +322,7 @@ UpdateVersionDialog::UpdateVersionDialog(wxWindow *parent) auto sizer_button = new wxBoxSizer(wxHORIZONTAL); - + StateColor btn_bg_green(std::pair(wxColour(27, 136, 68), StateColor::Pressed), std::pair(wxColour(61, 203, 115), StateColor::Hovered), std::pair(AMS_CONTROL_BRAND_COLOUR, StateColor::Normal)); @@ -202,19 +350,19 @@ UpdateVersionDialog::UpdateVersionDialog(wxWindow *parent) m_button_cancel->SetMinSize(wxSize(FromDIP(58), FromDIP(24))); m_button_cancel->SetCornerRadius(FromDIP(12)); - m_button_cancel->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent &e) { - EndModal(wxID_NO); + m_button_cancel->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent &e) { + EndModal(wxID_NO); }); - + sizer_button->Add(m_remind_choice, 0, wxALL | wxEXPAND, FromDIP(5)); sizer_button->AddStretchSpacer(); sizer_button->Add(m_button_ok, 0, wxALL, FromDIP(5)); sizer_button->Add(m_button_cancel, 0, wxALL, FromDIP(5)); - + m_sizer_right->Add(m_simplebook_release_note, 0, wxEXPAND | wxRIGHT, FromDIP(20)); m_sizer_right->Add(sizer_button, 0, wxEXPAND | wxRIGHT, FromDIP(20)); - + m_sizer_body->Add(m_sizer_right, 1, wxBOTTOM | wxEXPAND, FromDIP(8)); m_sizer_main->Add(m_sizer_body, 0, wxEXPAND, 0); m_sizer_main->Add(0, 0, 0, wxBOTTOM, 10); @@ -312,7 +460,7 @@ std::vector UpdateVersionDialog::splitWithStl(std::string str,std:: } void UpdateVersionDialog::update_version_info(wxString release_note, wxString version) -{ +{ //bbs check whether the web display is used bool use_web_link = false; std::string url_line = ""; @@ -341,7 +489,7 @@ void UpdateVersionDialog::update_version_info(wxString release_note, wxString ve m_scrollwindows_release_note->SetSizer(sizer_text_release_note); m_scrollwindows_release_note->Layout(); m_scrollwindows_release_note->Fit(); - } + } } SecondaryCheckDialog::SecondaryCheckDialog(wxWindow* parent, wxWindowID id, const wxString& title, enum ButtonStyle btn_style, const wxPoint& pos, const wxSize& size, long style, bool not_show_again_check) diff --git a/src/slic3r/GUI/ReleaseNote.hpp b/src/slic3r/GUI/ReleaseNote.hpp index 19fbdc25a..0031431c7 100644 --- a/src/slic3r/GUI/ReleaseNote.hpp +++ b/src/slic3r/GUI/ReleaseNote.hpp @@ -53,6 +53,20 @@ public: wxScrolledWindow *m_vebview_release_note {nullptr}; }; +class UpdatePluginDialog : public DPIDialog +{ +public: + UpdatePluginDialog(wxWindow* parent = nullptr); + ~UpdatePluginDialog(); + + void on_dpi_changed(const wxRect& suggested_rect) override; + void update_info(std::string json_path); + + wxStaticText* m_text_up_info{ nullptr }; + Label* operation_tips{ nullptr }; + wxScrolledWindow* m_vebview_release_note{ nullptr }; +}; + class UpdateVersionDialog : public DPIDialog { public: diff --git a/src/slic3r/Utils/PresetUpdater.cpp b/src/slic3r/Utils/PresetUpdater.cpp index 2f6953395..b6a4a5ed6 100644 --- a/src/slic3r/Utils/PresetUpdater.cpp +++ b/src/slic3r/Utils/PresetUpdater.cpp @@ -231,10 +231,11 @@ struct PresetUpdater::priv void prune_tmps() const; void sync_version() const; void parse_version_string(const std::string& body) const; - void sync_resources(std::string http_url, std::map &resources, bool check_patch = false, std::string current_version=""); + void sync_resources(std::string http_url, std::map &resources, bool check_patch = false, std::string current_version="", std::string changelog_file=""); void sync_config(std::string http_url, const VendorMap vendors); void sync_tooltip(std::string http_url, std::string language); void sync_plugins(std::string http_url, std::string plugin_version); + bool get_cached_plugins_version(std::string& cached_version); //BBS: refine preset update logic bool install_bundles_rsrc(std::vector bundles, bool snapshot) const; @@ -482,7 +483,7 @@ void PresetUpdater::priv::parse_version_string(const std::string& body) const //BBS: refine the Preset Updater logic // Download vendor indices. Also download new bundles if an index indicates there's a new one available. // Both are saved in cache. -void PresetUpdater::priv::sync_resources(std::string http_url, std::map &resources, bool check_patch, std::string current_version_str) +void PresetUpdater::priv::sync_resources(std::string http_url, std::map &resources, bool check_patch, std::string current_version_str, std::string changelog_file) { std::map resource_list; @@ -616,15 +617,26 @@ void PresetUpdater::priv::sync_resources(std::string http_url, std::mapsecond.description.empty()) { - // save the description to disk - std::string changelog_file = (cache_path / "changelog").string(); + // save the description to disk + if (changelog_file.empty()) + changelog_file = (cache_path / "changelog.json").string(); + else + changelog_file = (cache_path / changelog_file).string(); + + try { + json j; + //record the headers + j["version"] = resource_update->second.version; + j["description"] = resource_update->second.description; boost::nowide::ofstream c; c.open(changelog_file, std::ios::out | std::ios::trunc); - c << resource_update->second.description << std::endl; + c << std::setw(4) << j << std::endl; c.close(); } + catch(std::exception &err) { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__<< ": save to "<> j; + + cached_version = j["version"]; + } + catch(nlohmann::detail::parse_error &err) { + BOOST_LOG_TRIVIAL(error) << __FUNCTION__<< ": parse "< resources { {"slicer/plugins/cloud", { using_version, "", "", cache_path.string(), {"plugins"}}} }; - sync_resources(http_url, resources, true, plugin_version); + sync_resources(http_url, resources, true, plugin_version, "network_plugins.json"); } catch (std::exception& e) { BOOST_LOG_TRIVIAL(warning) << format("[BBL Updater] sync_plugins: %1%", e.what()); } + + bool result = get_cached_plugins_version(cached_version); + if (result) { + BOOST_LOG_TRIVIAL(info) << format("[BBL Updater] found new plugins: %1%, prompt to update", cached_version); + GUI::wxGetApp().plater()->get_notification_manager()->push_notification(GUI::NotificationType::BBLPluginUpdateAvailable); + } }