diff --git a/src/framework/cloud/qml/Muse/Cloud/CloudScoresView.qml b/src/framework/cloud/qml/Muse/Cloud/CloudScoresView.qml index 0682acc58ab4a..f5d3c32d44c6d 100644 --- a/src/framework/cloud/qml/Muse/Cloud/CloudScoresView.qml +++ b/src/framework/cloud/qml/Muse/Cloud/CloudScoresView.qml @@ -217,7 +217,7 @@ ScoresView { anchors.rightMargin: root.sideMargin title: qsTrc("project", "Unable to load online scores") - body: qsTrc("project", "Please check your internet connection or try again later.") + body: qsTrc("global", "Please check your internet connection or try again later.") } } } diff --git a/src/framework/learn/qml/Muse/Learn/internal/Playlist.qml b/src/framework/learn/qml/Muse/Learn/internal/Playlist.qml index af259c2dee11d..0c84f538997c2 100644 --- a/src/framework/learn/qml/Muse/Learn/internal/Playlist.qml +++ b/src/framework/learn/qml/Muse/Learn/internal/Playlist.qml @@ -139,7 +139,7 @@ FocusScope { StyledTextLabel { width: parent.width - text: qsTrc("learn", "Please check your internet connection or try again later.") + text: qsTrc("global", "Please check your internet connection or try again later.") } } } diff --git a/src/musesounds/CMakeLists.txt b/src/musesounds/CMakeLists.txt index f8a54f02efbb2..544785354e9e1 100644 --- a/src/musesounds/CMakeLists.txt +++ b/src/musesounds/CMakeLists.txt @@ -4,7 +4,7 @@ # MuseScore # Music Composition & Notation # -# Copyright (C) 2021 MuseScore BVBA and others +# Copyright (C) 2024 MuseScore BVBA and others # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3 as @@ -26,6 +26,14 @@ set(MODULE_QML_IMPORT ${CMAKE_CURRENT_LIST_DIR}/qml) set(MODULE_SRC ${CMAKE_CURRENT_LIST_DIR}/musesoundsmodule.cpp ${CMAKE_CURRENT_LIST_DIR}/musesoundsmodule.h + ${CMAKE_CURRENT_LIST_DIR}/imusesoundsrepository.h + ${CMAKE_CURRENT_LIST_DIR}/imusesoundsconfiguration.h + ${CMAKE_CURRENT_LIST_DIR}/musesoundstypes.h + + ${CMAKE_CURRENT_LIST_DIR}/internal/musesoundsrepository.cpp + ${CMAKE_CURRENT_LIST_DIR}/internal/musesoundsrepository.h + ${CMAKE_CURRENT_LIST_DIR}/internal/musesoundsconfiguration.cpp + ${CMAKE_CURRENT_LIST_DIR}/internal/musesoundsconfiguration.h ${CMAKE_CURRENT_LIST_DIR}/view/musesoundslistmodel.cpp ${CMAKE_CURRENT_LIST_DIR}/view/musesoundslistmodel.h diff --git a/src/musesounds/imusesoundsconfiguration.h b/src/musesounds/imusesoundsconfiguration.h new file mode 100644 index 0000000000000..5411705ee250e --- /dev/null +++ b/src/musesounds/imusesoundsconfiguration.h @@ -0,0 +1,40 @@ +/* + * SPDX-License-Identifier: GPL-3.0-only + * MuseScore-CLA-applies + * + * MuseScore + * Music Composition & Notation + * + * Copyright (C) 2024 MuseScore BVBA and others + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once + +#include "modularity/imoduleinterface.h" + +#include "network/networktypes.h" + +namespace mu::musesounds { +class IMuseSoundsConfiguration : MODULE_EXPORT_INTERFACE +{ + INTERFACE_ID(IMuseSoundsConfiguration) + +public: + virtual ~IMuseSoundsConfiguration() = default; + + virtual muse::network::RequestHeaders headers() const = 0; + + virtual QUrl soundsUrl() const = 0; +}; +} diff --git a/src/musesounds/imusesoundsrepository.h b/src/musesounds/imusesoundsrepository.h new file mode 100644 index 0000000000000..23db3b5109871 --- /dev/null +++ b/src/musesounds/imusesoundsrepository.h @@ -0,0 +1,40 @@ +/* + * SPDX-License-Identifier: GPL-3.0-only + * MuseScore-CLA-applies + * + * MuseScore + * Music Composition & Notation + * + * Copyright (C) 2024 MuseScore BVBA and others + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once + +#include "modularity/imoduleinterface.h" + +#include "async/notification.h" +#include "musesoundstypes.h" + +namespace mu::musesounds { +class IMuseSoundsRepository : MODULE_EXPORT_INTERFACE +{ + INTERFACE_ID(IMuseSoundsRepository) + +public: + virtual ~IMuseSoundsRepository() = default; + + virtual const MuseSoundCategoryInfoList& soundsCategoryList() const = 0; + virtual muse::async::Notification soundsCategoryListChanged() const = 0; +}; +} diff --git a/src/musesounds/internal/musesoundsconfiguration.cpp b/src/musesounds/internal/musesoundsconfiguration.cpp new file mode 100644 index 0000000000000..2eed98c5633d5 --- /dev/null +++ b/src/musesounds/internal/musesoundsconfiguration.cpp @@ -0,0 +1,54 @@ +/* + * SPDX-License-Identifier: GPL-3.0-only + * MuseScore-CLA-applies + * + * MuseScore + * Music Composition & Notation + * + * Copyright (C) 2024 MuseScore BVBA and others + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include "musesoundsconfiguration.h" + +#include "settings.h" + +using namespace mu::musesounds; +using namespace muse; +using namespace muse::network; + +static const std::string module_name("musesounds"); +static const Settings::Key GET_SOUNDS_TESTING_MODE_KEY(module_name, "musesounds/getSoundsTestingMode"); + +void MuseSoundsConfiguration::init() +{ + settings()->setDefaultValue(GET_SOUNDS_TESTING_MODE_KEY, Val(false)); +} + +RequestHeaders MuseSoundsConfiguration::headers() const +{ + RequestHeaders headers; + headers.rawHeaders["Accept"] = "application/json"; + return headers; +} + +QUrl MuseSoundsConfiguration::soundsUrl() const +{ + return !isTestingMode() ? QUrl("https://cosmos-customer-webservice.azurewebsites.net/graphql") + : QUrl("https://cosmos-customer-webservice-dev.azurewebsites.net/graphql"); +} + +bool MuseSoundsConfiguration::isTestingMode() const +{ + return settings()->value(GET_SOUNDS_TESTING_MODE_KEY).toBool(); +} diff --git a/src/musesounds/internal/musesoundsconfiguration.h b/src/musesounds/internal/musesoundsconfiguration.h new file mode 100644 index 0000000000000..f239363033621 --- /dev/null +++ b/src/musesounds/internal/musesoundsconfiguration.h @@ -0,0 +1,47 @@ +/* + * SPDX-License-Identifier: GPL-3.0-only + * MuseScore-CLA-applies + * + * MuseScore + * Music Composition & Notation + * + * Copyright (C) 2024 MuseScore BVBA and others + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once + +#include "modularity/ioc.h" +#include "iglobalconfiguration.h" + +#include "imusesoundsconfiguration.h" + +namespace mu::musesounds { +class MuseSoundsConfiguration : public IMuseSoundsConfiguration, public muse::Injectable +{ + Inject globalConfiguration = { this }; + +public: + MuseSoundsConfiguration(const muse::modularity::ContextPtr& iocCtx) + : Injectable(iocCtx) {} + + void init(); + + muse::network::RequestHeaders headers() const override; + + QUrl soundsUrl() const override; + +private: + bool isTestingMode() const; +}; +} diff --git a/src/musesounds/internal/musesoundsrepository.cpp b/src/musesounds/internal/musesoundsrepository.cpp new file mode 100644 index 0000000000000..00944dab20bba --- /dev/null +++ b/src/musesounds/internal/musesoundsrepository.cpp @@ -0,0 +1,149 @@ +/* + * SPDX-License-Identifier: GPL-3.0-only + * MuseScore-CLA-applies + * + * MuseScore + * Music Composition & Notation + * + * Copyright (C) 2024 MuseScore BVBA and others + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "musesoundsrepository.h" + +#include "serialization/json.h" + +#include "global/concurrency/concurrent.h" + +using namespace mu::musesounds; +using namespace muse; +using namespace muse::network; + +void MuseSoundsRepository::init() +{ + auto soundsCallBack = [this](const RetVal& result) { + if (!result.ret) { + LOGE() << result.ret.toString(); + return; + } + + LOGE() << result.ret.toString(); + + m_soundsCategories = result.val; + m_soundsCategoriesChanged.notify(); + }; + + Concurrent::run(this, &MuseSoundsRepository::th_requestSounds, soundsRequestUrl(), soundsCallBack); +} + +const MuseSoundCategoryInfoList& MuseSoundsRepository::soundsCategoryList() const +{ + return m_soundsCategories; +} + +async::Notification MuseSoundsRepository::soundsCategoryListChanged() const +{ + return m_soundsCategoriesChanged; +} + +QUrl MuseSoundsRepository::soundsRequestUrl() const +{ + String locale = QLocale().name(); + + String query = String( + R"( + query MyQuery { + product_pages_configuration(version: "default") { + librariesPageSections { + ... on ProductPageSectionRegular { + title(locale: {locale: "%1"}) + productCards { + ... on ProductCardRegular { + title(locale: {locale: "%1"}) + coverImageUrl + description(locale: {locale: "%1"}) + } + } + } + } + } + } + )").arg(locale); + + StringList params = { + "query=" + query + }; + + QUrl url = configuration()->soundsUrl(); + url.setQuery(params.join(u"&")); + + return url; +} + +void MuseSoundsRepository::th_requestSounds(const QUrl& soundsUrl, std::function)> callBack) const +{ + TRACEFUNC; + + network::INetworkManagerPtr networkManager = networkManagerCreator()->makeNetworkManager(); + RequestHeaders headers = configuration()->headers(); + + QBuffer soundsInfoData; + Ret soundsItemsRet = networkManager->get(soundsUrl, &soundsInfoData, headers); + if (!soundsItemsRet) { + callBack(soundsItemsRet); + return; + } + + JsonDocument soundsInfoDoc = JsonDocument::fromJson(ByteArray::fromQByteArray(soundsInfoData.data())); + + RetVal result; + result.ret = make_ret(Ret::Code::Ok); + result.val = parseSounds(soundsInfoDoc); + + callBack(result); +} + +MuseSoundCategoryInfoList MuseSoundsRepository::parseSounds(const JsonDocument& soundsDoc) const +{ + MuseSoundCategoryInfoList result; + + JsonObject obj = soundsDoc.rootObject(); + JsonObject data = !obj.empty() ? obj.value("data").toObject() : JsonObject(); + JsonObject productsSearch = !data.empty() ? data.value("products_search").toObject() : JsonObject(); + JsonArray items = !productsSearch.empty() ? productsSearch.value("items").toArray() : JsonArray(); + + for (size_t i = 0; i < items.size(); i++) { + JsonObject itemObj = items.at(i).toObject(); + + MuseSoundCategoryInfo category; + category.title = itemObj.value("title").toString(); + + JsonArray soundsItems = itemObj.value("items").toArray(); + + for (size_t i = 0; i < soundsItems.size(); i++) { + JsonObject soundItemObj = soundsItems.at(i).toObject(); + + MuseSoundInfo sound; + sound.title = itemObj.value("title").toString(); + sound.description = itemObj.value("description").toString(); + sound.thumbnail = itemObj.value("coverImageUrl").toString(); + + category.sounds.emplace_back(sound); + } + + result.emplace_back(category); + } + + return result; +} diff --git a/src/musesounds/internal/musesoundsrepository.h b/src/musesounds/internal/musesoundsrepository.h new file mode 100644 index 0000000000000..b7940a61839f2 --- /dev/null +++ b/src/musesounds/internal/musesoundsrepository.h @@ -0,0 +1,59 @@ +/* + * SPDX-License-Identifier: GPL-3.0-only + * MuseScore-CLA-applies + * + * MuseScore + * Music Composition & Notation + * + * Copyright (C) 2024 MuseScore BVBA and others + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include "modularity/ioc.h" +#include "network/inetworkmanagercreator.h" +#include "imusesoundsconfiguration.h" + +#include "imusesoundsrepository.h" + +namespace muse { +class JsonDocument; +} + +namespace mu::musesounds { +class MuseSoundsRepository : public IMuseSoundsRepository, public muse::Injectable +{ + Inject networkManagerCreator = { this }; + Inject configuration = { this }; + +public: + MuseSoundsRepository(const muse::modularity::ContextPtr& iocCtx) + : Injectable(iocCtx) {} + + void init(); + + const MuseSoundCategoryInfoList& soundsCategoryList() const override; + muse::async::Notification soundsCategoryListChanged() const override; + +private: + QUrl soundsRequestUrl() const; + void th_requestSounds(const QUrl& soundsUrl, std::function)> callBack) const; + + MuseSoundCategoryInfoList parseSounds(const muse::JsonDocument& soundsDoc) const; + + MuseSoundCategoryInfoList m_soundsCategories; + muse::async::Notification m_soundsCategoriesChanged; +}; +} diff --git a/src/musesounds/musesoundsmodule.cpp b/src/musesounds/musesoundsmodule.cpp index 5ceb3ecc5fc0e..3bb58d5f1605e 100644 --- a/src/musesounds/musesoundsmodule.cpp +++ b/src/musesounds/musesoundsmodule.cpp @@ -5,7 +5,7 @@ * MuseScore Studio * Music Composition & Notation * - * Copyright (C) 2021 MuseScore Limited + * Copyright (C) 2024 MuseScore Limited * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as @@ -23,6 +23,9 @@ #include +#include "internal/musesoundsconfiguration.h" +#include "internal/musesoundsrepository.h" + #include "view/musesoundslistmodel.h" using namespace mu::musesounds; @@ -40,6 +43,11 @@ std::string MuseSoundsModule::moduleName() const void MuseSoundsModule::registerExports() { + m_configuration = std::make_shared(iocContext()); + m_repository = std::make_shared(iocContext()); + + ioc()->registerExport(moduleName(), m_configuration); + ioc()->registerExport(moduleName(), m_repository); } void MuseSoundsModule::resolveImports() @@ -53,9 +61,15 @@ void MuseSoundsModule::registerResources() void MuseSoundsModule::registerUiTypes() { - qmlRegisterType("MuseScore.AppShell", 1, 0, "MuseSoundsListModel"); + qmlRegisterType("MuseScore.MuseSounds", 1, 0, "MuseSoundsListModel"); } -void MuseSoundsModule::onInit(const IApplication::RunMode&) +void MuseSoundsModule::onInit(const IApplication::RunMode& mode) { + if (mode != IApplication::RunMode::GuiApp) { + return; + } + + m_configuration->init(); + m_repository->init(); } diff --git a/src/musesounds/musesoundsmodule.h b/src/musesounds/musesoundsmodule.h index 1a452b1941e30..606e47bd9f926 100644 --- a/src/musesounds/musesoundsmodule.h +++ b/src/musesounds/musesoundsmodule.h @@ -5,7 +5,7 @@ * MuseScore Studio * Music Composition & Notation * - * Copyright (C) 2021 MuseScore Limited + * Copyright (C) 2024 MuseScore Limited * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as @@ -27,6 +27,8 @@ #include "modularity/imodulesetup.h" namespace mu::musesounds { +class MuseSoundsConfiguration; +class MuseSoundsRepository; class MuseSoundsModule : public muse::modularity::IModuleSetup { public: @@ -37,5 +39,9 @@ class MuseSoundsModule : public muse::modularity::IModuleSetup void registerResources() override; void registerUiTypes() override; void onInit(const muse::IApplication::RunMode& mode) override; + +private: + std::shared_ptr m_configuration; + std::shared_ptr m_repository; }; } diff --git a/src/musesounds/musesoundstypes.h b/src/musesounds/musesoundstypes.h new file mode 100644 index 0000000000000..126567b816b56 --- /dev/null +++ b/src/musesounds/musesoundstypes.h @@ -0,0 +1,41 @@ +/* + * SPDX-License-Identifier: GPL-3.0-only + * MuseScore-CLA-applies + * + * MuseScore + * Music Composition & Notation + * + * Copyright (C) 2024 MuseScore BVBA and others + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once + +#include "types/string.h" +#include "io/path.h" + +namespace mu::musesounds { +struct MuseSoundInfo { + muse::String title; + muse::String description; + muse::io::path_t thumbnail; +}; +using MuseSoundInfoList = std::vector; + +struct MuseSoundCategoryInfo { + muse::String title; + + MuseSoundInfoList sounds; +}; +using MuseSoundCategoryInfoList = std::vector; +} diff --git a/src/musesounds/qml/MuseScore/MuseSounds/MuseSoundsPage.qml b/src/musesounds/qml/MuseScore/MuseSounds/MuseSoundsPage.qml index bef14037a0f78..6940b3ca08b6c 100644 --- a/src/musesounds/qml/MuseScore/MuseSounds/MuseSoundsPage.qml +++ b/src/musesounds/qml/MuseScore/MuseSounds/MuseSoundsPage.qml @@ -5,7 +5,7 @@ * MuseScore Studio * Music Composition & Notation * - * Copyright (C) 2021 MuseScore Limited + * Copyright (C) 2024 MuseScore Limited * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as @@ -25,8 +25,9 @@ import QtQuick.Layouts 1.15 import Muse.Ui 1.0 import Muse.UiComponents 1.0 +import MuseScore.MuseSounds 1.0 -import MuseScore.AppShell 1.0 +import "internal" FocusScope { id: root @@ -124,21 +125,20 @@ FocusScope { spacing: 22 Repeater { - model: museSoundsModel.categories + model: museSoundsModel delegate: MuseSoundsListView { width: parent.width + title: modelData.title visible: count > 0 - categoryId: modelData.id - - model: museSoundsModel + model: modelData.sounds flickableItem: column navigationPanel.section: navSec - navigationPanel.name: categoryId + "Sounds" + navigationPanel.name: title + "Sounds" navigationPanel.order: index onGetSoundRequested: { @@ -153,6 +153,30 @@ FocusScope { } } + Column { + id: errorMessageColumn + visible: museSoundsModel.isEmpty + + anchors.top: parent.top + //! NOTE: should be synchronized with the error message from Learn page + anchors.topMargin: 127 + topGradient.height + Math.max(parent.height / 3 - height / 2, 0) + anchors.left: parent.left + anchors.right: parent.right + + spacing: 16 + + StyledTextLabel { + width: parent.width + font: ui.theme.tabBoldFont + text: qsTrc("musesounds", "Sorry, we are unable to load these sounds right now") + } + + StyledTextLabel { + width: parent.width + text: qsTrc("global", "Please check your internet connection or try again later.") + } + } + GradientRectangle { id: bottomGradient anchors.left: parent.left diff --git a/src/musesounds/qml/MuseScore/MuseSounds/internal/MuseSoundItem.qml b/src/musesounds/qml/MuseScore/MuseSounds/internal/MuseSoundItem.qml index 3f5ce5a3d31b8..2be98ad3cb7f2 100644 --- a/src/musesounds/qml/MuseScore/MuseSounds/internal/MuseSoundItem.qml +++ b/src/musesounds/qml/MuseScore/MuseSounds/internal/MuseSoundItem.qml @@ -5,7 +5,7 @@ * MuseScore * Music Composition & Notation * - * Copyright (C) 2021 MuseScore BVBA and others + * Copyright (C) 2024 MuseScore BVBA and others * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as diff --git a/src/musesounds/qml/MuseScore/MuseSounds/internal/MuseSoundsListView.qml b/src/musesounds/qml/MuseScore/MuseSounds/internal/MuseSoundsListView.qml index 77336a6363227..1f020fab37a22 100644 --- a/src/musesounds/qml/MuseScore/MuseSounds/internal/MuseSoundsListView.qml +++ b/src/musesounds/qml/MuseScore/MuseSounds/internal/MuseSoundsListView.qml @@ -5,7 +5,7 @@ * MuseScore * Music Composition & Notation * - * Copyright (C) 2021 MuseScore BVBA and others + * Copyright (C) 2024 MuseScore BVBA and others * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as @@ -28,13 +28,11 @@ import Muse.Extensions 1.0 Column { id: root - property alias model: filterModel.sourceModel + property alias model: view.model readonly property alias count: view.count property alias title: titleLabel.text - property string categoryId: "" - property var flickableItem: null property int headerHeight: titleLabel.height + spacing @@ -57,18 +55,6 @@ Column { view.itemAtIndex(0).requestActive() } - SortFilterProxyModel { - id: filterModel - - filters: [ - FilterValue { - roleName: "categoryId" - roleValue: root.categoryId - compareType: CompareType.Contains - } - ] - } - StyledTextLabel { id: titleLabel width: parent.width @@ -88,8 +74,6 @@ Column { height: contentHeight - spacingBetweenRows - model: filterModel - // We don't want this GridView to be scrollable; it would conflict with the containing Flickable. interactive: false highlightFollowsCurrentItem: false // prevent automatic scrolling @@ -110,11 +94,11 @@ Column { width: view.cellWidth function requestActive() { - _item.navigation.requestActive() + soundItem.navigation.requestActive() } MuseSoundItem { - id: _item + id: soundItem width: view.actualCellWidth height: view.actualCellHeight @@ -130,8 +114,8 @@ Column { navigation.row: view.columns === 0 ? 0 : Math.floor(model.index / view.columns) navigation.column: model.index - (navigation.row * view.columns) navigation.onActiveChanged: { - var pos = _item.mapToItem(root.flickableItem, 0, 0) - var rect = Qt.rect(pos.x, pos.y, _item.width, _item.height) + var pos = soundItem.mapToItem(root.flickableItem, 0, 0) + var rect = Qt.rect(pos.x, pos.y, soundItem.width, soundItem.height) root.navigationActivated(rect) } diff --git a/src/musesounds/view/musesoundslistmodel.cpp b/src/musesounds/view/musesoundslistmodel.cpp index 99242a205a2ff..9a24d3b79e55c 100644 --- a/src/musesounds/view/musesoundslistmodel.cpp +++ b/src/musesounds/view/musesoundslistmodel.cpp @@ -5,7 +5,7 @@ * MuseScore Studio * Music Composition & Notation * - * Copyright (C) 2021 MuseScore Limited + * Copyright (C) 2024 MuseScore Limited * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as @@ -26,49 +26,38 @@ using namespace mu::musesounds; -MuseSoundsListModel::MuseSoundsListModel(QObject* parent) - : QAbstractListModel(parent), Injectable(muse::iocCtxForQmlObject(this)) +static const QVariantMap soundInfoToMap(const MuseSoundInfo& soundInfo) { + QVariantMap map; + map["title"] = soundInfo.title.toQString(); + map["description"] = soundInfo.description.toQString(); + map["thumbnail"] = QUrl::fromLocalFile(soundInfo.thumbnail.toQString()); + + return map; } -void MuseSoundsListModel::load() +static const QVariantList soundInfoListToVariantList(const MuseSoundInfoList& soundInfoList) { - beginResetModel(); - - m_sounds = { - { u"symphony-brass", u"Symphony Brass", u"The UK's finest brass players expertly recorded at the world-famous AIR Studios.", "", - u"Trending" }, - { u"Harpsichord", u"Harpsichord", u"Performed by London harpsichord virtuoso Steven Devine.", "", - u"Trending" }, - { u"Muse Woodwinds", u"Muse Woodwinds", u"A stunning collection of 17 solo woodwind instruments.", "", - u"Trending" }, - - { u"Muse Strings", u"Muse Strings", u"An incredible free collection of sectional and solo strings", "", - u"Muse Group" }, - { u"Muse Keys", u"Muse Keys", u"An essential collection of keyboard instruments for use in your scores.", "", - u"Muse Group" }, - { u"Muse Percussion", u"Muse Percussion", u"A huge battery of orchestral and epic percussion.", "", - u"Muse Group" }, - { u"Muse Woodwinds", u"Muse Woodwinds", u"A stunning collection of 17 solo woodwind instruments.", "", - u"Muse Group" } - }; + QVariantList list; - std::sort(m_sounds.begin(), m_sounds.end(), [](const MuseSoundInfo& l, const MuseSoundInfo& r) { - return l.order < r.order; - }); + for (const MuseSoundInfo& soundInfo : soundInfoList) { + list << soundInfoToMap(soundInfo); + } - endResetModel(); + return list; +} - m_categories = { - { u"Trending", u"Trending", 0 }, - { u"Muse Group", u"Muse Group", 1 } - }; +MuseSoundsListModel::MuseSoundsListModel(QObject* parent) + : QAbstractListModel(parent), Injectable(muse::iocCtxForQmlObject(this)) +{ +} - std::sort(m_categories.begin(), m_categories.end(), [](const MuseSoundCategoryInfo& l, const MuseSoundCategoryInfo& r) { - return l.order < r.order; +void MuseSoundsListModel::load() +{ + setSoundsCategories(repository()->soundsCategoryList()); + repository()->soundsCategoryListChanged().onNotify(this, [this](){ + setSoundsCategories(repository()->soundsCategoryList()); }); - - emit categoriesChanged(); } QVariant MuseSoundsListModel::data(const QModelIndex& index, int role) const @@ -77,23 +66,13 @@ QVariant MuseSoundsListModel::data(const QModelIndex& index, int role) const return QVariant(); } - MuseSoundInfo soundInfo = m_sounds.at(index.row()); + const MuseSoundCategoryInfo& soundCategoryInfo = m_soundsCategories.at(index.row()); switch (role) { - case rCode: - return soundInfo.id.toQString(); case rTitle: - return soundInfo.title.toQString(); - case rDescription: - return soundInfo.description.toQString(); - case rThumbnailUrl: - if (soundInfo.thumbnail.empty()) { - return "qrc:/qml/Muse/Extensions/internal/resources/placeholder.png"; // todo - } - - return QUrl::fromLocalFile(soundInfo.thumbnail.toQString()); - case rCategoryId: - return soundInfo.categoryId.toQString(); + return soundCategoryInfo.title.toQString(); + case rSounds: + return soundInfoListToVariantList(soundCategoryInfo.sounds); } return QVariant(); @@ -101,31 +80,29 @@ QVariant MuseSoundsListModel::data(const QModelIndex& index, int role) const int MuseSoundsListModel::rowCount(const QModelIndex&) const { - return static_cast(m_sounds.size()); + return static_cast(m_soundsCategories.size()); } QHash MuseSoundsListModel::roleNames() const { return { - { rCode, "codeKey" }, { rTitle, "title" }, - { rDescription, "description" }, - { rThumbnailUrl, "thumbnailUrl" }, - { rCategoryId, "categoryId" } + { rSounds, "sounds" } }; } -QVariantList MuseSoundsListModel::categories() const +bool MuseSoundsListModel::isEmpty() const { - QVariantList result; + return m_soundsCategories.empty(); +} + +void MuseSoundsListModel::setSoundsCategories(const MuseSoundCategoryInfoList& soundsCategories) +{ + beginResetModel(); - for (const MuseSoundCategoryInfo& categoryInfo : m_categories) { - QVariantMap obj; - obj["id"] = categoryInfo.id.toQString(); - obj["title"] = categoryInfo.title.toQString(); + m_soundsCategories = soundsCategories; - result << obj; - } + endResetModel(); - return result; + emit isEmptyChanged(); } diff --git a/src/musesounds/view/musesoundslistmodel.h b/src/musesounds/view/musesoundslistmodel.h index df19ddcb29421..29ca9045385ea 100644 --- a/src/musesounds/view/musesoundslistmodel.h +++ b/src/musesounds/view/musesoundslistmodel.h @@ -5,7 +5,7 @@ * MuseScore Studio * Music Composition & Notation * - * Copyright (C) 2021 MuseScore Limited + * Copyright (C) 2024 MuseScore Limited * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as @@ -24,37 +24,19 @@ #include +#include "async/asyncable.h" + #include "modularity/ioc.h" -#include "context/iglobalcontext.h" -#include "iglobalconfiguration.h" +#include "imusesoundsrepository.h" namespace mu::musesounds { -struct MuseSoundCategoryInfo { - muse::String id; - muse::String title; - int order = -1; -}; -using MuseSoundCategoryInfoList = std::vector; - -struct MuseSoundInfo { - muse::String id; - muse::String title; - muse::String description; - muse::io::path_t thumbnail; - muse::String categoryId; - int order = -1; -}; -using MuseSoundInfoList = std::vector; - -class MuseSoundsListModel : public QAbstractListModel, public muse::Injectable +class MuseSoundsListModel : public QAbstractListModel, public muse::async::Asyncable, public muse::Injectable { Q_OBJECT - Q_PROPERTY(QVariantList categories READ categories NOTIFY categoriesChanged) + Q_PROPERTY(bool isEmpty READ isEmpty NOTIFY isEmptyChanged) - // Inject interactive = { this }; - // Inject provider = { this }; - // Inject configuration = { this }; + Inject repository = { this }; public: explicit MuseSoundsListModel(QObject* parent = nullptr); @@ -65,21 +47,19 @@ class MuseSoundsListModel : public QAbstractListModel, public muse::Injectable Q_INVOKABLE void load(); - QVariantList categories() const; + bool isEmpty() const; signals: - void categoriesChanged(); + void isEmptyChanged(); private: enum Roles { - rCode = Qt::UserRole + 1, - rTitle, - rDescription, - rThumbnailUrl, - rCategoryId + rTitle = Qt::UserRole + 1, + rSounds }; - MuseSoundInfoList m_sounds; - MuseSoundCategoryInfoList m_categories; + void setSoundsCategories(const MuseSoundCategoryInfoList& soundsCategories); + + MuseSoundCategoryInfoList m_soundsCategories; }; }