diff --git a/src/appshell/CMakeLists.txt b/src/appshell/CMakeLists.txt index 65b51dc7ca..417d6f0cc1 100644 --- a/src/appshell/CMakeLists.txt +++ b/src/appshell/CMakeLists.txt @@ -69,6 +69,8 @@ set(MODULE_SRC ${CMAKE_CURRENT_LIST_DIR}/view/toolsmenucontroller.h ${CMAKE_CURRENT_LIST_DIR}/view/helpmenucontroller.cpp ${CMAKE_CURRENT_LIST_DIR}/view/helpmenucontroller.h + ${CMAKE_CURRENT_LIST_DIR}/view/generalpreferencesmodel.cpp + ${CMAKE_CURRENT_LIST_DIR}/view/generalpreferencesmodel.h ${DOCKWINDOW_SRC} ) diff --git a/src/appshell/appshellmodule.cpp b/src/appshell/appshellmodule.cpp index 5febc54a58..1c818ea1cb 100644 --- a/src/appshell/appshellmodule.cpp +++ b/src/appshell/appshellmodule.cpp @@ -44,6 +44,7 @@ #include "view/toolsmenucontroller.h" #include "view/helpmenucontroller.h" #include "view/preferencesmodel.h" +#include "view/generalpreferencesmodel.h" using namespace mu::appshell; using namespace mu::framework; @@ -123,6 +124,7 @@ void AppShellModule::registerUiTypes() qmlRegisterType("MuseScore.Preferences", 1, 0, "SettingListModel"); qmlRegisterType("MuseScore.Preferences", 1, 0, "PreferencesModel"); + qmlRegisterType("MuseScore.Preferences", 1, 0, "GeneralPreferencesModel"); qmlRegisterType("MuseScore.AppMenu", 1, 0, "AppMenuModel"); qmlRegisterType("MuseScore.AppShell", 1, 0, "NotationPageModel"); qmlRegisterType("MuseScore.AppShell", 1, 0, "AboutModel"); diff --git a/src/appshell/qml/Preferences/GeneralPreferencesPage.qml b/src/appshell/qml/Preferences/GeneralPreferencesPage.qml index cb0d9fcaa8..480f550de7 100644 --- a/src/appshell/qml/Preferences/GeneralPreferencesPage.qml +++ b/src/appshell/qml/Preferences/GeneralPreferencesPage.qml @@ -1,19 +1,183 @@ import QtQuick 2.15 +import QtQuick.Controls 2.15 import MuseScore.Ui 1.0 import MuseScore.UiComponents 1.0 +import MuseScore.Preferences 1.0 Item { id: root + Component.onCompleted: { + preferencesModel.load() + } + + GeneralPreferencesModel { + id: preferencesModel + } + Rectangle { anchors.fill: parent color: ui.theme.backgroundSecondaryColor + } - StyledTextLabel { - anchors.centerIn: parent - text: qsTrc("appshell", "General") + Column { + anchors.fill: parent + spacing: 24 + + Column { + anchors.left: parent.left + anchors.right: parent.right + spacing: 18 + + StyledTextLabel { + text: qsTrc("appshell", "Languages") + font: ui.theme.bodyBoldFont + } + + Row { + spacing: 12 + + StyledComboBox { + width: 208 + + property var currValue + + textRoleName: "name" + valueRoleName: "code" + + model: preferencesModel.languages + + currentIndex: indexOfValue(preferencesModel.currentLanguageCode) + + onValueChanged: { + preferencesModel.currentLanguageCode = value + } + } + + FlatButton { + text: qsTrc("appshell", "Update Translations") + } + } + } + + SeparatorLine { } + + Column { + anchors.left: parent.left + anchors.right: parent.right + spacing: 18 + + StyledTextLabel { + text: qsTrc("appshell", "Telemetry") + font: ui.theme.bodyBoldFont + } + + CheckBox { + width: 216 + text: qsTrc("appshell", "Send anonymous telemetry data to MuseScore") + + checked: preferencesModel.isTelemetryAllowed + + onClicked: { + preferencesModel.isTelemetryAllowed = !preferencesModel.isTelemetryAllowed + } + } + } + + SeparatorLine { } + + Column { + anchors.left: parent.left + anchors.right: parent.right + spacing: 18 + + StyledTextLabel { + text: qsTrc("appshell", "Auto Save") + font: ui.theme.bodyBoldFont + } + + Row { + anchors.left: parent.left + anchors.right: parent.right + spacing: 0 + + CheckBox { + width: 216 + text: qsTrc("appshell", "Auto save every:") + + checked: preferencesModel.isAutoSave + + onClicked: { + preferencesModel.isAutoSave = !preferencesModel.isAutoSave + } + } + + IncrementalPropertyControl { + width: 96 + iconMode: iconModeEnum.hidden + + enabled: preferencesModel.isAutoSave + + currentValue: preferencesModel.autoSavePeriod + minValue: 1 + maxValue: 100 + step: 1 + + measureUnitsSymbol: qsTrc("appshell", "min") + + onValueEdited: { +// preferencesModel.autoSavePeriod = newValue + } + } + } + } + + SeparatorLine { } + + Column { + anchors.left: parent.left + anchors.right: parent.right + spacing: 18 + + StyledTextLabel { + text: qsTrc("appshell", "OSC Remote Control") + font: ui.theme.bodyBoldFont + } + + Row { + anchors.left: parent.left + anchors.right: parent.right + spacing: 0 + + CheckBox { + width: 216 + text: qsTrc("appshell", "Port number:") + + checked: preferencesModel.isOSCRemoteControl + + onClicked: { + preferencesModel.isOSCRemoteControl = !preferencesModel.isOSCRemoteControl + } + } + + IncrementalPropertyControl { + width: 96 + iconMode: iconModeEnum.hidden + + enabled: preferencesModel.isOSCRemoteControl + + currentValue: preferencesModel.oscPort + minValue: 1 + maxValue: 65535 + step: 1 + + onValueEdited: { + preferencesModel.oscPort = newValue + } + } + } } } } diff --git a/src/appshell/qml/Preferences/PreferencesDialog.qml b/src/appshell/qml/Preferences/PreferencesDialog.qml index 2b2ca3e686..b3292918a2 100644 --- a/src/appshell/qml/Preferences/PreferencesDialog.qml +++ b/src/appshell/qml/Preferences/PreferencesDialog.qml @@ -80,6 +80,7 @@ QmlDialog { Loader { Layout.fillHeight: true Layout.fillWidth: true + Layout.margins: 30 sourceComponent: Boolean(root.privatesProperties.inited) ? root.privatesProperties.pagesComponents[preferencesModel.currentPageId] : null diff --git a/src/appshell/view/generalpreferencesmodel.cpp b/src/appshell/view/generalpreferencesmodel.cpp new file mode 100644 index 0000000000..79b4cdd82e --- /dev/null +++ b/src/appshell/view/generalpreferencesmodel.cpp @@ -0,0 +1,149 @@ +//============================================================================= +// MuseScore +// Music Composition & Notation +// +// Copyright (C) 2021 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 2. +// +// 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +//============================================================================= +#include "generalpreferencesmodel.h" + +#include "log.h" + +using namespace mu::appshell; +using namespace mu::languages; + +GeneralPreferencesModel::GeneralPreferencesModel(QObject* parent) + : QObject(parent) +{ +} + +void GeneralPreferencesModel::load() +{ + languagesService()->currentLanguage().ch.onReceive(this, [this](const Language&) { + emit currentLanguageCodeChanged(currentLanguageCode()); + }); + + languagesService()->languages().ch.onReceive(this, [this](const LanguagesHash&) { + emit languagesChanged(languages()); + }); + + telemetryConfiguration()->isTelemetryAllowed().ch.onReceive(this, [this](bool) { + emit isTelemetryAllowedChanged(isTelemetryAllowed()); + }); +} + +void GeneralPreferencesModel::updateTranslations() +{ + NOT_IMPLEMENTED; +} + +QVariantList GeneralPreferencesModel::languages() const +{ + ValCh languages = languagesService()->languages(); + QList languageList = languages.val.values(); + + QVariantList result; + + for (const Language& language: languageList) { + if (language.status == LanguageStatus::Status::NoInstalled + || language.status == LanguageStatus::Status::Undefined) { + continue; + } + + QVariantMap languageObj; + languageObj["code"] = language.code; + languageObj["name"] = language.name; + result << languageObj; + } + + std::sort(result.begin(), result.end(), [](const QVariant& l, const QVariant& r) { + return l.toMap().value("code").toString() < r.toMap().value("code").toString(); + }); + + return result; +} + +QString GeneralPreferencesModel::currentLanguageCode() const +{ + return languagesService()->currentLanguage().val.code; +} + +bool GeneralPreferencesModel::isTelemetryAllowed() const +{ + return telemetryConfiguration()->isTelemetryAllowed().val; +} + +bool GeneralPreferencesModel::isAutoSave() const +{ + return false; +} + +int GeneralPreferencesModel::autoSavePeriod() const +{ + return 0; +} + +bool GeneralPreferencesModel::isOSCRemoteControl() const +{ + return false; +} + +int GeneralPreferencesModel::oscPort() const +{ + return 0; +} + +void GeneralPreferencesModel::setCurrentLanguageCode(QString currentLanguageCode) +{ + if (currentLanguageCode == this->currentLanguageCode()) { + return; + } + + languagesService()->setCurrentLanguage(currentLanguageCode); + emit currentLanguageCodeChanged(currentLanguageCode); +} + +void GeneralPreferencesModel::setIsTelemetryAllowed(bool isTelemetryAllowed) +{ + if (isTelemetryAllowed == this->isTelemetryAllowed()) { + return; + } + + telemetryConfiguration()->setIsTelemetryAllowed(isTelemetryAllowed); + emit isTelemetryAllowedChanged(isTelemetryAllowed); +} + +void GeneralPreferencesModel::setIsAutoSave(bool isAutoSave) +{ + NOT_IMPLEMENTED; + emit isAutoSaveChanged(isAutoSave); +} + +void GeneralPreferencesModel::setAutoSavePeriod(int autoSavePeriod) +{ + NOT_IMPLEMENTED; + emit autoSavePeriodChanged(autoSavePeriod); +} + +void GeneralPreferencesModel::setIsOSCRemoteControl(bool isOSCRemoteControl) +{ + NOT_IMPLEMENTED; + emit isOSCRemoteControlChanged(isOSCRemoteControl); +} + +void GeneralPreferencesModel::setOscPort(int oscPort) +{ + NOT_IMPLEMENTED; + emit oscPortChanged(oscPort); +} diff --git a/src/appshell/view/generalpreferencesmodel.h b/src/appshell/view/generalpreferencesmodel.h new file mode 100644 index 0000000000..faacf5407a --- /dev/null +++ b/src/appshell/view/generalpreferencesmodel.h @@ -0,0 +1,81 @@ +//============================================================================= +// MuseScore +// Music Composition & Notation +// +// Copyright (C) 2021 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 2. +// +// 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, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +//============================================================================= +#ifndef MU_APPSHELL_GENERALPREFERENCESMODEL_H +#define MU_APPSHELL_GENERALPREFERENCESMODEL_H + +#include + +#include "modularity/ioc.h" +#include "async/asyncable.h" + +#include "languages/ilanguagesservice.h" +#include "telemetry/itelemetryconfiguration.h" + +namespace mu::appshell { +class GeneralPreferencesModel : public QObject, public async::Asyncable +{ + Q_OBJECT + + INJECT(appshell, languages::ILanguagesService, languagesService) + INJECT(appshell, telemetry::ITelemetryConfiguration, telemetryConfiguration) + + Q_PROPERTY(QVariantList languages READ languages NOTIFY languagesChanged) + Q_PROPERTY(QString currentLanguageCode READ currentLanguageCode WRITE setCurrentLanguageCode NOTIFY currentLanguageCodeChanged) + + Q_PROPERTY(bool isTelemetryAllowed READ isTelemetryAllowed WRITE setIsTelemetryAllowed NOTIFY isTelemetryAllowedChanged) + Q_PROPERTY(bool isAutoSave READ isAutoSave WRITE setIsAutoSave NOTIFY isAutoSaveChanged) + Q_PROPERTY(int autoSavePeriod READ autoSavePeriod WRITE setAutoSavePeriod NOTIFY autoSavePeriodChanged) + Q_PROPERTY(bool isOSCRemoteControl READ isOSCRemoteControl WRITE setIsOSCRemoteControl NOTIFY isOSCRemoteControlChanged) + Q_PROPERTY(int oscPort READ oscPort WRITE setOscPort NOTIFY oscPortChanged) + +public: + explicit GeneralPreferencesModel(QObject* parent = nullptr); + + Q_INVOKABLE void load(); + Q_INVOKABLE void updateTranslations(); + + QVariantList languages() const; + QString currentLanguageCode() const; + + bool isTelemetryAllowed() const; + bool isAutoSave() const; + int autoSavePeriod() const; + bool isOSCRemoteControl() const; + int oscPort() const; + +public slots: + void setCurrentLanguageCode(QString currentLanguageCode); + void setIsTelemetryAllowed(bool isTelemetryAllowed); + void setIsAutoSave(bool isAutoSave); + void setAutoSavePeriod(int sutoSavePeriod); + void setIsOSCRemoteControl(bool isOSCRemoteControl); + void setOscPort(int oscPort); + +signals: + void languagesChanged(QVariantList languages); + void currentLanguageCodeChanged(QString currentLanguageCode); + void isTelemetryAllowedChanged(bool isTelemetryAllowed); + void isAutoSaveChanged(bool isAutoSave); + void isOSCRemoteControlChanged(bool isOSCRemoteControl); + void oscPortChanged(int oscPort); + void autoSavePeriodChanged(int autoSavePeriod); +}; +} + +#endif // MU_APPSHELL_GENERALPREFERENCESMODEL_H diff --git a/src/framework/telemetry/internal/telemetryconfiguration.cpp b/src/framework/telemetry/internal/telemetryconfiguration.cpp index 95c94a4c8c..886a9e8063 100644 --- a/src/framework/telemetry/internal/telemetryconfiguration.cpp +++ b/src/framework/telemetry/internal/telemetryconfiguration.cpp @@ -33,6 +33,10 @@ void TelemetryConfiguration::init() settings()->setDefaultValue(REQUEST_TELEMETRY_PERMISSION, Val(true)); settings()->setDefaultValue(IS_TELEMETRY_ALLOWED, Val(false)); settings()->setDefaultValue(IS_DUMP_UPLOAD_ALLOWED, Val(true)); + + settings()->valueChanged(IS_TELEMETRY_ALLOWED).onReceive(this, [this](const Val& allowed){ + m_isTelemetryAllowedChannel.send(allowed.toBool()); + }); } bool TelemetryConfiguration::needRequestTelemetryPermission() const @@ -40,10 +44,14 @@ bool TelemetryConfiguration::needRequestTelemetryPermission() const return settings()->value(REQUEST_TELEMETRY_PERMISSION).toBool(); } -bool TelemetryConfiguration::isTelemetryAllowed() const +mu::ValCh TelemetryConfiguration::isTelemetryAllowed() const { + mu::ValCh allowed; + allowed.ch = m_isTelemetryAllowedChannel; static QString id(TELEMETRY_TRACK_ID); - return !id.isEmpty() && settings()->value(IS_TELEMETRY_ALLOWED).toBool(); + allowed.val = !id.isEmpty() && settings()->value(IS_TELEMETRY_ALLOWED).toBool(); + + return allowed; } void TelemetryConfiguration::setIsTelemetryAllowed(bool val) diff --git a/src/framework/telemetry/internal/telemetryconfiguration.h b/src/framework/telemetry/internal/telemetryconfiguration.h index 3632ec8df6..f120f0d6f7 100644 --- a/src/framework/telemetry/internal/telemetryconfiguration.h +++ b/src/framework/telemetry/internal/telemetryconfiguration.h @@ -20,9 +20,10 @@ #define MU_TELEMETRY_TELEMETRYCONFIGURATION_H #include "../itelemetryconfiguration.h" +#include "async/asyncable.h" namespace mu::telemetry { -class TelemetryConfiguration : public ITelemetryConfiguration +class TelemetryConfiguration : public ITelemetryConfiguration, public async::Asyncable { public: TelemetryConfiguration() = default; @@ -31,11 +32,14 @@ public: bool needRequestTelemetryPermission() const override; - bool isTelemetryAllowed() const override; + ValCh isTelemetryAllowed() const override; void setIsTelemetryAllowed(bool val) override; bool isDumpUploadAllowed() const override; void setIsDumpUploadAllowed(bool val) override; + +private: + async::Channel m_isTelemetryAllowedChannel; }; } diff --git a/src/framework/telemetry/internal/telemetryservice.cpp b/src/framework/telemetry/internal/telemetryservice.cpp index 21689ab8b8..d72516bd0f 100644 --- a/src/framework/telemetry/internal/telemetryservice.cpp +++ b/src/framework/telemetry/internal/telemetryservice.cpp @@ -64,5 +64,5 @@ void TelemetryService::endSession() bool TelemetryService::isTelemetryAllowed() const { - return configuration()->isTelemetryAllowed(); + return configuration()->isTelemetryAllowed().val; } diff --git a/src/framework/telemetry/itelemetryconfiguration.h b/src/framework/telemetry/itelemetryconfiguration.h index 337eb1feb2..5d6fdc0514 100644 --- a/src/framework/telemetry/itelemetryconfiguration.h +++ b/src/framework/telemetry/itelemetryconfiguration.h @@ -20,6 +20,7 @@ #define MU_TELEMETRY_ITELEMETRYCONFIGURATION_H #include "modularity/imoduleexport.h" +#include "retval.h" namespace mu::telemetry { class ITelemetryConfiguration : MODULE_EXPORT_INTERFACE @@ -31,7 +32,7 @@ public: virtual bool needRequestTelemetryPermission() const = 0; - virtual bool isTelemetryAllowed() const = 0; + virtual ValCh isTelemetryAllowed() const = 0; virtual void setIsTelemetryAllowed(bool val) = 0; virtual bool isDumpUploadAllowed() const = 0; diff --git a/src/framework/uicomponents/qml/MuseScore/UiComponents/CheckBox.qml b/src/framework/uicomponents/qml/MuseScore/UiComponents/CheckBox.qml index 1b08da4d8e..d6ba4ba195 100644 --- a/src/framework/uicomponents/qml/MuseScore/UiComponents/CheckBox.qml +++ b/src/framework/uicomponents/qml/MuseScore/UiComponents/CheckBox.qml @@ -53,6 +53,8 @@ FocusableItem { Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter horizontalAlignment: Text.AlignLeft + wrapMode: Text.WordWrap + maximumLineCount: 2 visible: Boolean(text) } diff --git a/src/languages/view/languagelistmodel.cpp b/src/languages/view/languagelistmodel.cpp index 17b579f4e0..470f3a2651 100644 --- a/src/languages/view/languagelistmodel.cpp +++ b/src/languages/view/languagelistmodel.cpp @@ -204,7 +204,7 @@ void LanguageListModel::uninstall(QString code) void LanguageListModel::openPreferences() { - interactive()->open("musescore://devtools"); + interactive()->open("musescore://preferences?currentPageId=general"); } QVariantMap LanguageListModel::language(QString code)