Line data Source code
1 : /*
2 : * SPDX-License-Identifier: GPL-3.0-only
3 : * MuseScore-CLA-applies
4 : *
5 : * MuseScore Studio
6 : * Music Composition & Notation
7 : *
8 : * Copyright (C) 2025 MuseScore Limited and others
9 : *
10 : * This program is free software: you can redistribute it and/or modify
11 : * it under the terms of the GNU General Public License version 3 as
12 : * published by the Free Software Foundation.
13 : *
14 : * This program is distributed in the hope that it will be useful,
15 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : * GNU General Public License for more details.
18 : *
19 : * You should have received a copy of the GNU General Public License
20 : * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 : */
22 :
23 : #include "musesoundscheckupdatescenario.h"
24 :
25 : #include "musesoundserrors.h"
26 :
27 : #include "global/translation.h"
28 : #include "global/containers.h"
29 : #include "global/stringutils.h"
30 : #include "global/defer.h"
31 : #include "global/log.h"
32 :
33 : using namespace muse;
34 : using namespace mu::musesounds;
35 : using namespace muse::update;
36 :
37 0 : bool MuseSoundsCheckUpdateScenario::needCheckForUpdate() const
38 : {
39 0 : return configuration()->needCheckForMuseSoundsUpdate();
40 : }
41 :
42 0 : void MuseSoundsCheckUpdateScenario::checkForUpdate(bool manual)
43 : {
44 0 : if (m_checkInProgress) {
45 0 : return;
46 : }
47 :
48 0 : m_checkInProgress = true;
49 0 : m_checkInProgressChanged.notify();
50 :
51 0 : LOGI() << "Checking for MuseSounds update...";
52 :
53 0 : service()->checkForUpdate().onResolve(this, [this, manual](const RetVal<ReleaseInfo>& res) {
54 0 : DEFER {
55 0 : m_checkInProgress = false;
56 0 : m_checkInProgressChanged.notify();
57 0 : };
58 :
59 0 : if (!res.ret) {
60 0 : if (res.ret.code() != static_cast<int>(Err::NoUpdate)) {
61 0 : LOGE() << "Unable to check for MuseSounds update: " << res.ret.toString();
62 : }
63 0 : return;
64 : }
65 :
66 0 : if (manual && !shouldIgnoreUpdate(res.val)) {
67 0 : showReleaseInfo(res.val);
68 : }
69 0 : });
70 : }
71 :
72 0 : bool MuseSoundsCheckUpdateScenario::checkInProgress() const
73 : {
74 0 : return m_checkInProgress;
75 : }
76 :
77 0 : async::Notification MuseSoundsCheckUpdateScenario::checkInProgressChanged() const
78 : {
79 0 : return m_checkInProgressChanged;
80 : }
81 :
82 0 : bool MuseSoundsCheckUpdateScenario::hasUpdate() const
83 : {
84 0 : if (m_checkInProgress || !service()->needCheckForUpdate()) {
85 0 : return false;
86 : }
87 :
88 0 : const RetVal<ReleaseInfo>& lastCheckResult = service()->lastCheckResult();
89 0 : if (!lastCheckResult.ret) {
90 0 : return false;
91 : }
92 :
93 0 : if (lastCheckResult.ret.code() == static_cast<int>(Err::NoUpdate)) {
94 0 : return false;
95 : }
96 :
97 0 : return !shouldIgnoreUpdate(lastCheckResult.val);
98 : }
99 :
100 0 : muse::Ret MuseSoundsCheckUpdateScenario::showUpdate()
101 : {
102 0 : const RetVal<ReleaseInfo>& lastCheckResult = service()->lastCheckResult();
103 0 : if (!lastCheckResult.ret) {
104 0 : return lastCheckResult.ret;
105 : }
106 :
107 0 : return showReleaseInfo(lastCheckResult.val);
108 : }
109 :
110 0 : bool MuseSoundsCheckUpdateScenario::shouldIgnoreUpdate(const ReleaseInfo& info) const
111 : {
112 0 : return info.version == configuration()->lastShownMuseSoundsReleaseVersion() && !configuration()->museSoundsCheckForUpdateTestMode();
113 : }
114 :
115 0 : void MuseSoundsCheckUpdateScenario::setIgnoredUpdate(const std::string& version)
116 : {
117 0 : configuration()->setLastShownMuseSoundsReleaseVersion(version);
118 0 : }
119 :
120 0 : muse::Ret MuseSoundsCheckUpdateScenario::showReleaseInfo(const ReleaseInfo& info)
121 : {
122 0 : Ret ret = make_ok();
123 :
124 0 : DEFER {
125 0 : if (ret || ret.code() == static_cast<int>(Ret::Code::Cancel)) {
126 0 : setIgnoredUpdate(info.version);
127 : }
128 0 : };
129 :
130 0 : UriQuery query("musescore://musesounds/musesoundsreleaseinfo");
131 :
132 0 : if (!configuration()->museSoundsCheckForUpdateTestMode()) {
133 0 : query.addParam("notes", Val(info.notes));
134 0 : query.addParam("features", Val(info.additionInfo.at("features")));
135 : }
136 :
137 0 : if (info.actionTitle.empty()) {
138 0 : query.addParam("actionTitle", Val(trc("musesounds", "Take me to MuseHub")));
139 : } else {
140 0 : query.addParam("actionTitle", Val(info.actionTitle));
141 : }
142 :
143 0 : if (info.cancelTitle.empty()) {
144 0 : query.addParam("cancelTitle", Val(trc("musesounds", "No thanks")));
145 : } else {
146 0 : query.addParam("cancelTitle", Val(info.cancelTitle));
147 : }
148 :
149 0 : if (info.imageUrl.empty()) {
150 0 : query.addParam("imageUrl", Val("qrc:/qt/qml/MuseScore/MuseSounds/resources/muse_sounds_promo.png"));
151 : } else {
152 0 : query.addParam("imageUrl", Val(info.imageUrl));
153 : }
154 :
155 0 : RetVal<Val> rv = interactive()->openSync(query);
156 0 : if (!rv.ret) {
157 0 : LOGD() << rv.ret.toString();
158 0 : ret = rv.ret;
159 0 : return ret;
160 : }
161 :
162 0 : std::string actionCode = rv.val.toString();
163 0 : if (actionCode == "openMuseHub") {
164 0 : tryOpenMuseHub(info.actions);
165 : }
166 :
167 0 : return ret;
168 0 : }
169 :
170 0 : void MuseSoundsCheckUpdateScenario::tryOpenMuseHub(ValList actions) const
171 : {
172 0 : if (actions.empty()) {
173 0 : LOGE() << "no actions to open MuseHub";
174 0 : return;
175 : }
176 :
177 0 : std::string action = muse::takeFirst(actions).toString();
178 0 : LOGI() << "try open: " << action;
179 :
180 0 : if (muse::strings::startsWith(action, "http")) { // or https
181 0 : platformInteractive()->openUrl(action);
182 0 : return;
183 : }
184 :
185 0 : platformInteractive()->openApp(muse::UriQuery(action)).onReject(this, [this, actions](int, const std::string&) {
186 0 : tryOpenMuseHub(actions);
187 0 : });
188 0 : }
|