diff --git a/src/framework/stubs/update/musesoundscheckupdateservicestub.cpp b/src/framework/stubs/update/musesoundscheckupdateservicestub.cpp index 057588f71c8c4..335536570bbb8 100644 --- a/src/framework/stubs/update/musesoundscheckupdateservicestub.cpp +++ b/src/framework/stubs/update/musesoundscheckupdateservicestub.cpp @@ -44,6 +44,6 @@ Progress MuseSoundsCheckUpdateServiceStub::updateProgress() return Progress(); } -void MuseSoundsCheckUpdateServiceStub::openMuseHub() +void MuseSoundsCheckUpdateServiceStub::openMuseHub(const std::vector&) { } diff --git a/src/framework/stubs/update/musesoundscheckupdateservicestub.h b/src/framework/stubs/update/musesoundscheckupdateservicestub.h index d305995bd9230..0a3972b2802cf 100644 --- a/src/framework/stubs/update/musesoundscheckupdateservicestub.h +++ b/src/framework/stubs/update/musesoundscheckupdateservicestub.h @@ -35,7 +35,7 @@ class MuseSoundsCheckUpdateServiceStub : public IMuseSoundsCheckUpdateService Progress updateProgress() override; - void openMuseHub() override; + void openMuseHub(const std::vector& actions) override; }; } diff --git a/src/framework/update/imusesoundscheckupdateservice.h b/src/framework/update/imusesoundscheckupdateservice.h index 7520371922da8..0014d4ba13509 100644 --- a/src/framework/update/imusesoundscheckupdateservice.h +++ b/src/framework/update/imusesoundscheckupdateservice.h @@ -23,7 +23,6 @@ #define MUSE_UPDATE_IMUSESOUNDSCHECKUPDATESERVICE_H #include "types/retval.h" -#include "io/path.h" #include "progress.h" #include "updatetypes.h" @@ -45,7 +44,7 @@ class IMuseSoundsCheckUpdateService : MODULE_EXPORT_INTERFACE virtual Progress updateProgress() = 0; - virtual void openMuseHub() = 0; + virtual void openMuseHub(const std::vector& actions) = 0; }; } diff --git a/src/framework/update/internal/musesoundscheckupdatescenario.cpp b/src/framework/update/internal/musesoundscheckupdatescenario.cpp index 5fd7bc97bcaf0..7a7a2a153c972 100644 --- a/src/framework/update/internal/musesoundscheckupdatescenario.cpp +++ b/src/framework/update/internal/musesoundscheckupdatescenario.cpp @@ -23,18 +23,21 @@ #include "musesoundscheckupdatescenario.h" #include "global/concurrency/concurrent.h" +#include "global/defer.h" +#include "global/types/val.h" +#include "global/types/translatablestring.h" #include "updateerrors.h" -#include "types/val.h" - -#include "defer.h" #include "log.h" using namespace muse; using namespace muse::update; using namespace muse::actions; +static const char* DEFAULT_IMAGE_URL = "qrc:/qml/Muse/Update/resources/muse_sounds_promo.png"; +static const TranslatableString DEFAULT_ACTION_TITLE("update", "Take me to Muse Hub"); + void MuseSoundsCheckUpdateScenario::delayedInit() { if (service()->needCheckForUpdate() && multiInstancesProvider()->instances().size() == 1) { @@ -141,6 +144,18 @@ void MuseSoundsCheckUpdateScenario::showReleaseInfo(const ReleaseInfo& info) query.addParam("notes", Val(info.notes)); query.addParam("features", Val(info.additionInfo.at("features"))); + if (info.actionTitle.empty()) { + query.addParam("actionTitle", Val(DEFAULT_ACTION_TITLE.qTranslated())); + } else { + query.addParam("actionTitle", Val(QString::fromStdString(info.actionTitle))); + } + + if (info.imageUrl.empty()) { + query.addParam("imageUrl", Val(QString(DEFAULT_IMAGE_URL))); + } else { + query.addParam("imageUrl", Val(QString::fromStdString(info.imageUrl))); + } + RetVal rv = interactive()->open(query); if (!rv.ret) { LOGD() << rv.ret.toString(); @@ -150,6 +165,6 @@ void MuseSoundsCheckUpdateScenario::showReleaseInfo(const ReleaseInfo& info) QString actionCode = rv.val.toQString(); if (actionCode == "openMuseHub") { - service()->openMuseHub(); + service()->openMuseHub(info.actions); } } diff --git a/src/framework/update/internal/musesoundscheckupdateservice.cpp b/src/framework/update/internal/musesoundscheckupdateservice.cpp index 1ee087fba8996..5209560ba95c4 100644 --- a/src/framework/update/internal/musesoundscheckupdateservice.cpp +++ b/src/framework/update/internal/musesoundscheckupdateservice.cpp @@ -29,13 +29,18 @@ #include #include +#include "global/types/version.h" +#include "global/containers.h" +#include "global/stringutils.h" + #include "../updateerrors.h" -#include "types/version.h" #include "defer.h" #include "log.h" static const muse::Uri MUSEHUB_APP_URI("musehub://?from=musescore"); +static const muse::Uri MUSEHUB_APP_V1_URI("muse-hub://?from=musescore"); +static const std::string MUSEHUB_WEB_URL = "https://www.musehub.com/"; using namespace muse::update; using namespace muse::network; @@ -118,29 +123,29 @@ muse::Progress MuseSoundsCheckUpdateService::updateProgress() return m_updateProgress; } -void MuseSoundsCheckUpdateService::openMuseHub() +void MuseSoundsCheckUpdateService::openMuseHub(const std::vector& actions) { - auto openMuseHubWebsite = [this]() { - static const std::string MUSEHUB_URL = "https://www.musehub.com/"; - interactive()->openUrl(MUSEHUB_URL); - }; + tryOpenMuseHub(actions); +} -#ifdef Q_OS_WIN - interactive()->openApp(MUSEHUB_APP_URI).onReject(this, [=](int, const std::string&) { - static const muse::Uri MUSEHUB_APP_V1_URI("muse-hub://?from=musescore"); - interactive()->openApp(MUSEHUB_APP_V1_URI).onReject(this, [=](int, const std::string&) { - openMuseHubWebsite(); - }); - }); - return; -#elif defined(Q_OS_MAC) - interactive()->openApp(MUSEHUB_APP_URI).onReject(this, [=](int, const std::string&) { - openMuseHubWebsite(); +void MuseSoundsCheckUpdateService::tryOpenMuseHub(std::vector actions) +{ + if (actions.empty()) { + LOGE() << "not actions to open Muse Hub"; + return; + } + + std::string action = muse::takeFirst(actions); + LOGI() << "try open: " << action; + + if (muse::strings::startsWith(action, "http")) { // or https + interactive()->openUrl(action); + return; + } + + interactive()->openApp(muse::Uri(action)).onReject(this, [this, actions](int, const std::string&) { + tryOpenMuseHub(actions); }); - return; -#else - openMuseHubWebsite(); -#endif } muse::RetVal MuseSoundsCheckUpdateService::parseRelease(const QByteArray& json) const @@ -154,6 +159,28 @@ muse::RetVal MuseSoundsCheckUpdateService::parseRelease(const QByte return result; } + /* + { + "version": String, + "image_url": String, // it can be base64 data, like "data:image/png;base64,iVBORw0KGgoA......" + "content": { + "locale_code": { + "notes": String, + "features": [String] + "action_title": String // title of action button + } + }, + + // open app or web page url, try in order, + // like this ["musehub://?from=musescore", "muse-hub://?from=musescore", "https://www.musehub.com"] + "actions": { + "windows": [String], + "macos": [String], + "linux": [String] + } + } + */ + QJsonObject releaseObj = jsonDoc.object(); if (releaseObj.empty()) { @@ -182,17 +209,55 @@ muse::RetVal MuseSoundsCheckUpdateService::parseRelease(const QByte result.ret = make_ok(); result.val.version = releaseObj.value("version").toString().toStdString(); + result.val.imageUrl = releaseObj.value("image_url").toString().toStdString(); result.val.notes = contentLocaleObj.value("notes").toString().toStdString(); - ValList featuresList; QJsonArray features = contentLocaleObj.value("features").toArray(); for (const QJsonValue& feature : features) { featuresList.push_back(Val(feature.toString().toStdString())); } - result.val.additionInfo.insert({ "features", Val(featuresList) }); + result.val.actionTitle = contentLocaleObj.value("action_title").toString().toStdString(); + QJsonObject actionsObj = releaseObj.value("actions").toObject(); + +#ifdef Q_OS_WIN + QJsonArray actionsArr = actionsObj.value("windows").toArray(); + for (const QJsonValue& a : actionsArr) { + result.val.actions.push_back(a.toString().toStdString()); + } + + // def + if (result.val.actions.empty()) { + result.val.actions.push_back(MUSEHUB_APP_URI.toString()); + result.val.actions.push_back(MUSEHUB_APP_V1_URI.toString()); + result.val.actions.push_back(MUSEHUB_WEB_URL); + } + +#elif defined(Q_OS_MAC) + QJsonArray actionsArr = actionsObj.value("macos").toArray(); + for (const QJsonValue& a : actionsArr) { + result.val.actions.push_back(a.toString().toStdString()); + } + + // def + if (result.val.actions.empty()) { + result.val.actions.push_back(MUSEHUB_APP_URI.toString()); + result.val.actions.push_back(MUSEHUB_WEB_URL); + } +#else + QJsonArray actionsArr = actionsObj.value("linux").toArray(); + for (const QJsonValue& a : actionsArr) { + result.val.actions.push_back(a.toString().toStdString()); + } + + // def + if (result.val.actions.empty()) { + result.val.actions.push_back(MUSEHUB_WEB_URL); + } +#endif + return result; } diff --git a/src/framework/update/internal/musesoundscheckupdateservice.h b/src/framework/update/internal/musesoundscheckupdateservice.h index fc581a2f49cfb..728ddaf501167 100644 --- a/src/framework/update/internal/musesoundscheckupdateservice.h +++ b/src/framework/update/internal/musesoundscheckupdateservice.h @@ -54,10 +54,11 @@ class MuseSoundsCheckUpdateService : public IMuseSoundsCheckUpdateService, publi Progress updateProgress() override; - void openMuseHub() override; + void openMuseHub(const std::vector& actions) override; private: RetVal parseRelease(const QByteArray& json) const; + void tryOpenMuseHub(std::vector actions); void clear(); diff --git a/src/framework/update/qml/Muse/Update/MuseSoundsReleaseInfoDialog.qml b/src/framework/update/qml/Muse/Update/MuseSoundsReleaseInfoDialog.qml index 2932c341e415f..3f8950539c7f3 100644 --- a/src/framework/update/qml/Muse/Update/MuseSoundsReleaseInfoDialog.qml +++ b/src/framework/update/qml/Muse/Update/MuseSoundsReleaseInfoDialog.qml @@ -33,6 +33,8 @@ StyledDialogView { property alias notes: view.notes property alias features: featuresViewRepeater.model + property alias imageUrl: image.source + property alias actionTitle: buttons.defaultButtonName contentWidth: 530 contentHeight: 510 @@ -78,7 +80,7 @@ StyledDialogView { Layout.fillWidth: true Layout.preferredHeight: 186 - source: "qrc:/qml/Muse/Update/resources/muse_sounds_promo.png" + //source: "qrc:/qml/Muse/Update/resources/muse_sounds_promo.png" } Item { diff --git a/src/framework/update/qml/Muse/Update/internal/MuseSoundsReleaseInfoBottomPanel.qml b/src/framework/update/qml/Muse/Update/internal/MuseSoundsReleaseInfoBottomPanel.qml index 50e45a9a138f9..34027cd816975 100644 --- a/src/framework/update/qml/Muse/Update/internal/MuseSoundsReleaseInfoBottomPanel.qml +++ b/src/framework/update/qml/Muse/Update/internal/MuseSoundsReleaseInfoBottomPanel.qml @@ -28,7 +28,7 @@ import Muse.UiComponents 1.0 RowLayout { id: root - property string defaultButtonName: openMuseHubButton.text + property alias defaultButtonName: openMuseHubButton.text property NavigationPanel navigationPanel: NavigationPanel { name: "UpdateBottomPanel" @@ -65,8 +65,6 @@ RowLayout { Layout.alignment: Qt.AlignVCenter Layout.preferredWidth: (root.width - root.spacing) / 2 - text: qsTrc("update", "Take me to Muse Hub") - accentButton: true navigation.name: "OpenMuseHubButton" diff --git a/src/framework/update/updatetypes.h b/src/framework/update/updatetypes.h index 6b373880c6b9a..c4a8777f1942b 100644 --- a/src/framework/update/updatetypes.h +++ b/src/framework/update/updatetypes.h @@ -47,11 +47,15 @@ struct ReleaseInfo { std::string fileName; std::string fileUrl; + std::string imageUrl; // it can be base64 data, like "data:image/png;base64,iVBORw0KGgoA......" std::string notes; PrevReleasesNotesList previousReleasesNotes; ValMap additionInfo; + std::string actionTitle; // title of action button + std::vector actions; // open app or web page url, try in order + bool isValid() const { return !version.empty();