Vital
Loading...
Searching...
No Matches
download_section.cpp
Go to the documentation of this file.
1
3
4#include "download_section.h"
5#include "load_save.h"
7
8#include "skin.h"
9#include "fonts.h"
10
11namespace {
12 const std::string kDownloadUrlPrefix = "";
13 const std::string kPacksUrlPrefix = "";
14 const std::string kTokenUrlQuery = "?idToken=";
15}
16
18 Overlay(std::move(name)), auth_(auth),
19 body_(Shaders::kRoundedRectangleFragment),
20 download_progress_(Shaders::kColorFragment),
21 download_background_(Shaders::kColorFragment),
22 install_text_background_(Shaders::kRoundedRectangleFragment),
23 install_thread_(this) {
24
25 cancel_ = false;
26 initial_download_ = !LoadSave::hasDataDirectory();
27 progress_value_ = 0.0f;
28
29 addOpenGlComponent(&body_);
30 addOpenGlComponent(&download_background_);
31 addOpenGlComponent(&install_text_background_);
32 download_progress_.addRoundedCorners();
33 addOpenGlComponent(&download_progress_);
34
35 logo_ = std::make_unique<AppLogo>("logo");
36 addOpenGlComponent(logo_.get());
37
38 loading_wheel_ = std::make_unique<LoadingWheel>();
39 addOpenGlComponent(loading_wheel_.get());
40
41 install_button_ = std::make_unique<OpenGlToggleButton>("Install");
42 install_button_->setText("Install");
43 install_button_->setUiButton(true);
44 install_button_->addListener(this);
45 install_button_->setEnabled(false);
46 addAndMakeVisible(install_button_.get());
47 addOpenGlComponent(install_button_->getGlComponent());
48
49 cancel_button_ = std::make_unique<OpenGlToggleButton>("Cancel");
50 cancel_button_->setText("Cancel");
51 cancel_button_->setUiButton(false);
52 cancel_button_->addListener(this);
53 addAndMakeVisible(cancel_button_.get());
54 addOpenGlComponent(cancel_button_->getGlComponent());
55
56 download_text_ = std::make_unique<PlainTextComponent>("Download", "Downloading factory content...");
57 addOpenGlComponent(download_text_.get());
58 download_text_->setFontType(PlainTextComponent::kLight);
59 download_text_->setTextSize(kTextHeight);
60 download_text_->setJustification(Justification::centred);
61
62 install_location_ = LoadSave::getDataDirectory();
63 install_location_text_ = std::make_unique<PlainTextComponent>("Location", install_location_.getFullPathName());
64 addOpenGlComponent(install_location_text_.get());
65 install_location_text_->setFontType(PlainTextComponent::kLight);
66 install_location_text_->setTextSize(kTextHeight);
67 install_location_text_->setJustification(Justification::centredLeft);
68
69 folder_button_ = std::make_unique<OpenGlShapeButton>("Folder");
70 addAndMakeVisible(folder_button_.get());
71 addOpenGlComponent(folder_button_->getGlComponent());
72#if !defined(NO_TEXT_ENTRY)
73 folder_button_->addListener(this);
74#endif
75 folder_button_->setTriggeredOnMouseDown(true);
76 folder_button_->setShape(Paths::folder());
77
78 available_packs_location_ = File::getSpecialLocation(File::tempDirectory).getChildFile("available_packs.json");
79}
80
82 static constexpr int kLogoWidth = 128;
83 static constexpr int kDownloadHeight = 8;
84 static constexpr float kRingThicknessRatio = 0.03f;
85 static constexpr float kRingMarginRatio = 0.03f;
87
89 Colour background = findColour(Skin::kBackground, true);
90 download_background_.setColor(background);
91 install_text_background_.setColor(background);
92 install_text_background_.setRounding(findValue(Skin::kWidgetRoundedCorner));
93 download_progress_.setColor(findColour(Skin::kWidgetPrimary1, true));
94
95 body_.setColor(findColour(Skin::kBody, true));
96
97 Rectangle<int> download_rect = getDownloadRect();
98 body_.setBounds(download_rect);
99
100 int logo_width = size_ratio_ * kLogoWidth;
101 int padding_x = size_ratio_ * kPaddingX;
102 int padding_y = size_ratio_ * kPaddingY;
103 int button_height = size_ratio_ * kButtonHeight;
104
105 int logo_x = (getWidth() - logo_width) / 2;
106 int logo_y = download_rect.getY() + padding_y;
107 logo_->setBounds(logo_x, logo_y, logo_width, logo_width);
108
109 int wheel_margin = logo_width * kRingMarginRatio;
110 loading_wheel_->setBounds(logo_->getX() - wheel_margin, logo_->getY() - wheel_margin,
111 logo_->getWidth() + 2 * wheel_margin, logo_->getHeight() + 2 * wheel_margin);
112 loading_wheel_->setThickness(logo_width * kRingThicknessRatio);
113
114 float button_width = (download_rect.getWidth() - 3 * padding_x) / 2;
115 install_button_->setBounds(download_rect.getX() + padding_x,
116 download_rect.getBottom() - padding_y - button_height,
117 button_width, button_height);
118 cancel_button_->setBounds(install_button_->getRight() + padding_x, install_button_->getY(),
119 download_rect.getRight() - 2 * padding_x - install_button_->getRight(), button_height);
120
121 float text_size = kTextHeight * size_ratio_;
122 download_text_->setTextSize(text_size);
123 float text_height = 22.0f * size_ratio_;
124 download_text_->setBounds(download_rect.getX() + padding_x, logo_y + logo_width + padding_y,
125 download_rect.getWidth() - 2 * padding_x, text_height);
126 int download_height = size_ratio_ * kDownloadHeight;
127 int download_y = (download_text_->getBottom() + install_button_->getY() -
128 download_height + text_size - text_height) / 2;
129 if (initial_download_) {
130 folder_button_->setBounds(install_button_->getX(), install_button_->getY() - padding_y - button_height,
131 button_height, button_height);
132 download_y = (download_text_->getBottom() + folder_button_->getY() - download_height + text_size - text_height) / 2;
133
134 install_location_text_->setTextSize(text_size);
135 int install_background_x = folder_button_->getRight() + text_height / 2;
136 int install_text_x = folder_button_->getRight() + text_height;
137 install_location_text_->setBounds(install_text_x, folder_button_->getY(),
138 download_rect.getRight() - padding_x - install_text_x, button_height);
139 install_text_background_.setBounds(install_background_x, folder_button_->getY(),
140 download_rect.getRight() - padding_x - install_background_x, button_height);
141 }
142
143 download_progress_.setBounds(install_button_->getX(), download_y,
144 download_rect.getWidth() - 2 * padding_x, download_height);
145 download_background_.setBounds(download_progress_.getBounds());
146}
147
148void DownloadSection::setVisible(bool should_be_visible) {
149 Overlay::setVisible(should_be_visible);
150
151 if (should_be_visible) {
152 Image image(Image::ARGB, 1, 1, false);
153 Graphics g(image);
155 }
156}
157
158void DownloadSection::mouseUp(const MouseEvent &e) {
159 if (install_text_background_.getBounds().contains(e.getPosition()))
161}
162
163void DownloadSection::buttonClicked(Button* clicked_button) {
164 if (clicked_button == cancel_button_.get())
166 else if (clicked_button == install_button_.get())
168 else if (clicked_button == folder_button_.get())
170}
171
173 download_progress_.setQuad(0, -1.0f, -1.0f, 2.0f * progress_value_, 2.0f);
174
176 download_progress_.renderCorners(open_gl, animate, download_progress_.getBodyColor(),
177 download_progress_.getHeight() / 2);
178}
179
180void DownloadSection::finished(URL::DownloadTask* task, bool success) {
181 if (cancel_)
182 return;
183
184 if (awaiting_install_.empty()) {
185 try {
186 json packs_data;
187 if (success)
188 packs_data = json::parse(available_packs_location_.loadFileAsString().toStdString(), nullptr, false);
189
190 if (available_packs_location_.exists() && LoadSave::getAvailablePacksFile() != File())
191 available_packs_location_.moveFileTo(LoadSave::getAvailablePacksFile());
192
193 json available_packs = packs_data["packs"];
194 json installed_packs = LoadSave::getInstalledPacks();
195
196 MessageManagerLock lock(Thread::getCurrentThread());
197 if (!lock.lockWasGained())
198 return;
199
200 for (auto& pack : available_packs) {
201 bool purchased = false;
202 if (pack.count("Purchased"))
203 purchased = pack["Purchased"];
204 int id = pack["Id"];
205 std::string pack_name = pack["Name"];
206 pack_name = String(pack_name).removeCharacters(" ._").toLowerCase().toStdString();
207
208 if (purchased && installed_packs.count(std::to_string(id)) == 0 && installed_packs.count(pack_name) == 0) {
209 std::string name = pack["Name"];
210 std::string author = pack["Author"];
211 std::string url = pack["DownloadLink"];
213
214 File download_location = File::getSpecialLocation(File::tempDirectory).getChildFile(name + ".zip");
215 if (!url.empty() && url[0] == '/')
216 url = kDownloadUrlPrefix + url;
217 awaiting_download_.emplace_back(name, author, id, URL(url), download_location);
218 }
219 }
220
221 if (awaiting_download_.empty()) {
222 for (Listener* listener : listeners_)
223 listener->noDownloadNeeded();
224 }
225 else
226 setVisible(true);
227 }
228 catch (const json::exception& e) {
229 LoadSave::writeErrorLog(e.what());
230 }
231 }
232 else {
233 progress_value_ = 1.0f;
234 awaiting_install_[awaiting_install_.size() - 1].finished = success;
235 }
236
237 if (!awaiting_download_.empty()) {
238 DownloadPack pack = awaiting_download_[awaiting_download_.size() - 1];
239 awaiting_download_.pop_back();
240 awaiting_install_.push_back(pack);
241 int number = static_cast<int>(awaiting_install_.size());
242 int total = awaiting_download_.size() + awaiting_install_.size();
243
244 MessageManagerLock lock(Thread::getCurrentThread());
245 if (!lock.lockWasGained())
246 return;
247
248 std::string order_string = "(" + std::to_string(number) + " / " + std::to_string(total) + ")";
249 download_text_->setText(pack.author + ": " + pack.name + " " + order_string);
250 download_threads_.emplace_back(std::make_unique<DownloadThread>(this, pack.url, pack.download_location));
251 download_threads_[download_threads_.size() - 1]->startThread();
252 return;
253 }
254
255 MessageManagerLock lock(Thread::getCurrentThread());
256 if (!lock.lockWasGained())
257 return;
258
259 if (success)
260 install_button_->setEnabled(true);
261
262 loading_wheel_->setActive(false);
263 download_text_->setText("Downloads completed");
264}
265
266void DownloadSection::progress(URL::DownloadTask* task, int64 bytesDownloaded, int64 totalLength) {
267 MessageManagerLock lock(Thread::getCurrentThread());
268
269 if (lock.lockWasGained() && !awaiting_install_.empty()) {
270 double completed = bytesDownloaded;
271 progress_value_ = completed / totalLength;
272 }
273}
274
276 int width = kDownloadWidth * size_ratio_;
277 int height = kDownloadInitialHeight * size_ratio_;
278 if (!initial_download_)
280
281 int x = (getWidth() - width) / 2;
282 int y = kY * size_ratio_;
283 return Rectangle<int>(x, y, width, height);
284}
285
287 cancel_ = false;
288 progress_value_ = 0.0f;
289 awaiting_install_.clear();
290 awaiting_download_.clear();
291 packs_url_ = URL(kPacksUrlPrefix + kTokenUrlQuery + auth_->token());
292 download_text_->setText("Getting available packs...");
293 loading_wheel_->setActive(true);
294 download_threads_.emplace_back(std::make_unique<DownloadThread>(this, packs_url_, available_packs_location_));
295 download_threads_[download_threads_.size() - 1]->startThread();
296}
297
299 install_location_.createDirectory();
300 File errors_file = install_location_.getChildFile("errors.txt");
301 errors_file.create();
302
303 if (!install_location_.exists() || !errors_file.exists() || !errors_file.hasWriteAccess()) {
304 MessageManagerLock lock(Thread::getCurrentThread());
305 String warning = "Can't create install directory. Select another destination";
306 AlertWindow::showNativeDialogBox("Can't Create Directory", warning, false);
307 install_button_->setEnabled(true);
308 cancel_button_->setEnabled(true);
309 return;
310 }
311
312 loading_wheel_->setActive(true);
313 download_text_->setText("Installing...");
314 install_button_->setEnabled(false);
315 cancel_button_->setEnabled(false);
316 install_thread_.startThread();
317}
318
319void DownloadSection::startDownload(Thread* thread, URL& url, const File& dest) {
320 download_tasks_.emplace_back(url.downloadToFile(dest, "", this));
321}
322
323void DownloadSection::startInstall(Thread* thread) {
324 std::vector<int> installed;
325 LoadSave::saveDataDirectory(install_location_);
326
327 for (const DownloadPack& pack : awaiting_install_) {
328 if (!pack.download_location.exists())
329 LoadSave::writeErrorLog("Install Error: Pack file moved or is missing.");
330
331 if (!pack.finished)
332 LoadSave::writeErrorLog("Install Error: Pack didn't download correctly");
333
334 if (!pack.finished || !pack.download_location.exists())
335 continue;
336
337 ZipFile zip(pack.download_location);
338 if (zip.getNumEntries() <= 0)
339 LoadSave::writeErrorLog("Unzipping Error: no entries");
340 else {
341 Result unzip_result = zip.uncompressTo(install_location_);
342 if (!unzip_result.wasOk())
343 LoadSave::writeErrorLog("Unzipping Error: " + unzip_result.getErrorMessage());
344 else
345 installed.push_back(pack.id);
346 }
347
348 pack.download_location.deleteFile();
349 }
350
351 MessageManagerLock lock(Thread::getCurrentThread());
352 if (!lock.lockWasGained())
353 return;
354 for (int installed_pack_id : installed)
355 LoadSave::markPackInstalled(installed_pack_id);
356
357 for (Listener* listener : listeners_)
358 listener->dataDirectoryChanged();
359
360 loading_wheel_->completeRing();
361 download_text_->setText("All done!");
362
363 startTimer(kCompletionWaitMs);
364}
365
367 cancel_ = true;
368 download_tasks_.clear();
369 setVisible(false);
370}
371
373 FileChooser open_box("Choose Install Directory", install_location_);
374 if (open_box.browseForDirectory()) {
375 File result = open_box.getResult();
376 if (result.getFileName() != "Vial")
377 result = result.getChildFile("Vial");
378
379 result.createDirectory();
380 File errors_file = result.getChildFile("errors.txt");
381 errors_file.create();
382
383 if (result.exists() && errors_file.exists() && errors_file.hasWriteAccess()) {
384 install_location_ = result;
385 install_location_text_->setText(install_location_.getFullPathName());
386 }
387 else {
388 String warning = "Can't create install directory. Select another destination";
389 AlertWindow::showNativeDialogBox("Invalid Directory", warning, false);
390 }
391 }
392}
A no-op stub implementation used when authentication is disabled.
Definition authentication.h:163
std::string token()
Returns an empty token string.
Definition authentication.h:174
Interface for objects that need to respond to data directory changes or no-download scenarios.
Definition download_section.h:54
void startDownload(Thread *thread, URL &url, const File &dest)
Definition download_section.cpp:319
void triggerInstall()
Starts the installation process after all downloads are completed.
Definition download_section.cpp:298
static constexpr int kDownloadAdditionalHeight
The additional height if more content is available.
Definition download_section.h:28
void renderOpenGlComponents(OpenGlWrapper &open_gl, bool animate) override
Definition download_section.cpp:172
static constexpr int kDownloadWidth
The width of the download UI.
Definition download_section.h:24
void triggerDownload()
Triggers the process of checking available packs and downloading necessary content.
Definition download_section.cpp:286
static constexpr int kTextHeight
The text height for labels.
Definition download_section.h:30
Rectangle< int > getDownloadRect()
Definition download_section.cpp:275
static constexpr int kY
The vertical offset for the download UI.
Definition download_section.h:22
void mouseUp(const MouseEvent &e) override
Definition download_section.cpp:158
void cancelDownload()
Cancels all ongoing downloads.
Definition download_section.cpp:366
void setVisible(bool should_be_visible) override
Definition download_section.cpp:148
void chooseInstallFolder()
Allows the user to choose a folder for installation.
Definition download_section.cpp:372
static constexpr int kPaddingX
Horizontal padding inside the UI.
Definition download_section.h:32
void progress(URL::DownloadTask *task, int64 bytesDownloaded, int64 totalLength) override
Definition download_section.cpp:266
void startInstall(Thread *thread)
Definition download_section.cpp:323
static constexpr int kButtonHeight
Height of buttons.
Definition download_section.h:36
static constexpr int kDownloadInitialHeight
The initial height of the download UI before any content is loaded.
Definition download_section.h:26
DownloadSection(String name, Authentication *auth)
Definition download_section.cpp:17
static constexpr int kPaddingY
Vertical padding inside the UI.
Definition download_section.h:34
void resized() override
Lays out the UI components within the overlay.
Definition download_section.cpp:81
static constexpr int kCompletionWaitMs
Time in milliseconds to wait before hiding the UI after completion.
Definition download_section.h:38
void finished(URL::DownloadTask *task, bool success) override
Definition download_section.cpp:180
void buttonClicked(Button *clicked_button) override
Definition download_section.cpp:163
static File getAvailablePacksFile()
Retrieves the file listing available packs.
Definition load_save.cpp:1428
static void markPackInstalled(int id)
Marks a pack as installed by ID in the packs file.
Definition load_save.cpp:1494
static File getDataDirectory()
Gets the current data directory from the config.
Definition load_save.cpp:1718
static json getInstalledPacks()
Returns a JSON list of installed packs.
Definition load_save.cpp:1470
static void saveDataDirectory(const File &data_directory)
Saves the given directory as the data directory in the configuration.
Definition load_save.cpp:1508
static void writeErrorLog(String error_log)
Appends an error message to an error log file.
Definition load_save.cpp:1140
static bool hasDataDirectory()
Checks if a data directory is properly configured (exists and has packs.json).
Definition load_save.cpp:1417
void addRoundedCorners()
Adds rounded corners to the component's edges.
Definition open_gl_component.cpp:138
void renderCorners(OpenGlWrapper &open_gl, bool animate, Colour color, float rounding)
Renders the corner shapes using the given color and rounding amount.
Definition open_gl_component.cpp:153
Colour getBodyColor() const
Retrieves the component's body color.
Definition open_gl_component.h:172
void setQuad(int i, float x, float y, float w, float h)
Sets the position and size of a quad in normalized device space.
Definition open_gl_multi_quad.h:313
force_inline void setColor(Colour color)
Sets the base color for the quads.
Definition open_gl_multi_quad.h:102
void setRounding(float rounding)
Sets the rounding radius of the quads.
Definition open_gl_multi_quad.h:347
A SynthSection that displays an overlay with a background and optional listeners.
Definition overlay.h:180
virtual void resized() override
Called when the overlay is resized. Updates background color and size.
Definition overlay.h:237
void setVisible(bool should_be_visible) override
Sets the visibility of the overlay and notifies listeners.
Definition overlay.h:224
float size_ratio_
A scaling factor for the overlay size.
Definition overlay.h:267
static Path folder()
Creates a folder icon path.
Definition paths.h:133
@ kLight
Definition open_gl_image_component.h:309
Manages and provides access to vertex and fragment shaders used by the OpenGL rendering pipeline.
Definition shaders.h:19
@ kBodyRounding
Definition skin.h:71
@ kWidgetRoundedCorner
Definition skin.h:104
@ kBackground
Definition skin.h:128
@ kWidgetPrimary1
Definition skin.h:165
@ kBody
Definition skin.h:129
virtual void renderOpenGlComponents(OpenGlWrapper &open_gl, bool animate)
Renders all OpenGL components in this section and sub-sections.
Definition synth_section.cpp:357
virtual void animate(bool animate)
Triggers animation state change in sub-sections if needed.
Definition synth_section.cpp:822
void paintOpenGlChildrenBackgrounds(Graphics &g)
Paints the backgrounds for all OpenGL child components.
Definition synth_section.cpp:267
float findValue(Skin::ValueId value_id) const
Finds a value in the skin overrides or from the parent if not found locally.
Definition synth_section.cpp:18
void addOpenGlComponent(OpenGlComponent *open_gl_component, bool to_beginning=false)
Definition synth_section.cpp:489
Declares the DownloadSection class, providing a UI for downloading and installing preset packs.
nlohmann::json json
Definition line_generator.h:7
Represents a downloadable pack with name, author, ID, URL, and local destination file.
Definition download_section.h:41
std::string author
The author of the pack.
Definition download_section.h:45
std::string name
The name of the pack.
Definition download_section.h:44
File download_location
The local file where the pack is downloaded.
Definition download_section.h:48
URL url
The download URL for the pack.
Definition download_section.h:47
A helper struct containing references to OpenGL context, shaders, and display scale.
Definition shaders.h:174