DownloadWidget.cpp 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. /*
  2. * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include "DownloadWidget.h"
  7. #include <AK/NumberFormat.h>
  8. #include <AK/StringBuilder.h>
  9. #include <LibCore/ConfigFile.h>
  10. #include <LibCore/File.h>
  11. #include <LibCore/FileStream.h>
  12. #include <LibCore/StandardPaths.h>
  13. #include <LibDesktop/Launcher.h>
  14. #include <LibGUI/BoxLayout.h>
  15. #include <LibGUI/Button.h>
  16. #include <LibGUI/CheckBox.h>
  17. #include <LibGUI/ImageWidget.h>
  18. #include <LibGUI/Label.h>
  19. #include <LibGUI/MessageBox.h>
  20. #include <LibGUI/Progressbar.h>
  21. #include <LibGUI/Window.h>
  22. #include <LibProtocol/RequestClient.h>
  23. #include <LibWeb/Loader/ResourceLoader.h>
  24. namespace Browser {
  25. DownloadWidget::DownloadWidget(const URL& url)
  26. : m_url(url)
  27. {
  28. {
  29. StringBuilder builder;
  30. builder.append(Core::StandardPaths::downloads_directory());
  31. builder.append('/');
  32. builder.append(m_url.basename());
  33. m_destination_path = builder.to_string();
  34. }
  35. auto browser_config = Core::ConfigFile::open_for_app("Browser");
  36. auto close_on_finish = browser_config->read_bool_entry("Preferences", "CloseDownloadWidgetOnFinish", false);
  37. m_elapsed_timer.start();
  38. m_download = Web::ResourceLoader::the().protocol_client().start_request("GET", url);
  39. VERIFY(m_download);
  40. m_download->on_progress = [this](Optional<u32> total_size, u32 downloaded_size) {
  41. did_progress(total_size.value(), downloaded_size);
  42. };
  43. {
  44. auto file_or_error = Core::File::open(m_destination_path, Core::OpenMode::WriteOnly);
  45. if (file_or_error.is_error()) {
  46. GUI::MessageBox::show(window(), String::formatted("Cannot open {} for writing", m_destination_path), "Download failed", GUI::MessageBox::Type::Error);
  47. window()->close();
  48. return;
  49. }
  50. m_output_file_stream = make<Core::OutputFileStream>(*file_or_error.value());
  51. }
  52. m_download->on_finish = [this](bool success, auto) { did_finish(success); };
  53. m_download->stream_into(*m_output_file_stream);
  54. set_fill_with_background_color(true);
  55. auto& layout = set_layout<GUI::VerticalBoxLayout>();
  56. layout.set_margins(4);
  57. auto& animation_container = add<GUI::Widget>();
  58. animation_container.set_fixed_height(32);
  59. auto& animation_layout = animation_container.set_layout<GUI::HorizontalBoxLayout>();
  60. m_browser_image = animation_container.add<GUI::ImageWidget>();
  61. m_browser_image->load_from_file("/res/graphics/download-animation.gif");
  62. animation_layout.add_spacer();
  63. auto& source_label = add<GUI::Label>(String::formatted("From: {}", url));
  64. source_label.set_text_alignment(Gfx::TextAlignment::CenterLeft);
  65. source_label.set_fixed_height(16);
  66. m_progressbar = add<GUI::Progressbar>();
  67. m_progressbar->set_fixed_height(20);
  68. m_progress_label = add<GUI::Label>();
  69. m_progress_label->set_text_alignment(Gfx::TextAlignment::CenterLeft);
  70. m_progress_label->set_fixed_height(16);
  71. auto& destination_label = add<GUI::Label>(String::formatted("To: {}", m_destination_path));
  72. destination_label.set_text_alignment(Gfx::TextAlignment::CenterLeft);
  73. destination_label.set_fixed_height(16);
  74. m_close_on_finish_checkbox = add<GUI::CheckBox>("Close when finished");
  75. m_close_on_finish_checkbox->set_checked(close_on_finish);
  76. m_close_on_finish_checkbox->on_checked = [&](bool checked) {
  77. auto browser_config = Core::ConfigFile::open_for_app("Browser", Core::ConfigFile::AllowWriting::Yes);
  78. browser_config->write_bool_entry("Preferences", "CloseDownloadWidgetOnFinish", checked);
  79. };
  80. auto& button_container = add<GUI::Widget>();
  81. auto& button_container_layout = button_container.set_layout<GUI::HorizontalBoxLayout>();
  82. button_container_layout.add_spacer();
  83. m_cancel_button = button_container.add<GUI::Button>("Cancel");
  84. m_cancel_button->set_fixed_size(100, 22);
  85. m_cancel_button->on_click = [this](auto) {
  86. bool success = m_download->stop();
  87. VERIFY(success);
  88. window()->close();
  89. };
  90. m_close_button = button_container.add<GUI::Button>("OK");
  91. m_close_button->set_enabled(false);
  92. m_close_button->set_fixed_size(100, 22);
  93. m_close_button->on_click = [this](auto) {
  94. window()->close();
  95. };
  96. }
  97. DownloadWidget::~DownloadWidget()
  98. {
  99. }
  100. void DownloadWidget::did_progress(Optional<u32> total_size, u32 downloaded_size)
  101. {
  102. m_progressbar->set_min(0);
  103. if (total_size.has_value()) {
  104. int percent = roundf(((float)downloaded_size / (float)total_size.value()) * 100.0f);
  105. window()->set_progress(percent);
  106. m_progressbar->set_max(total_size.value());
  107. } else {
  108. m_progressbar->set_max(0);
  109. }
  110. m_progressbar->set_value(downloaded_size);
  111. {
  112. StringBuilder builder;
  113. builder.append("Downloaded ");
  114. builder.append(human_readable_size(downloaded_size));
  115. builder.appendff(" in {} sec", m_elapsed_timer.elapsed() / 1000);
  116. m_progress_label->set_text(builder.to_string());
  117. }
  118. {
  119. StringBuilder builder;
  120. if (total_size.has_value()) {
  121. int percent = roundf(((float)downloaded_size / (float)total_size.value()) * 100);
  122. builder.appendff("{}%", percent);
  123. } else {
  124. builder.append(human_readable_size(downloaded_size));
  125. }
  126. builder.append(" of ");
  127. builder.append(m_url.basename());
  128. window()->set_title(builder.to_string());
  129. }
  130. }
  131. void DownloadWidget::did_finish(bool success)
  132. {
  133. dbgln("did_finish, success={}", success);
  134. m_browser_image->load_from_file("/res/graphics/download-finished.gif");
  135. window()->set_title("Download finished!");
  136. m_close_button->set_enabled(true);
  137. m_cancel_button->set_text("Open in Folder");
  138. m_cancel_button->on_click = [this](auto) {
  139. Desktop::Launcher::open(URL::create_with_file_protocol(Core::StandardPaths::downloads_directory(), m_url.basename()));
  140. window()->close();
  141. };
  142. m_cancel_button->update();
  143. if (!success) {
  144. GUI::MessageBox::show(window(), String::formatted("Download failed for some reason"), "Download failed", GUI::MessageBox::Type::Error);
  145. window()->close();
  146. return;
  147. }
  148. if (m_close_on_finish_checkbox->is_checked())
  149. window()->close();
  150. }
  151. }