2020-05-05 23:58:22 +02:00
/*
* Copyright ( c ) 2020 , Andreas Kling < kling @ serenityos . org >
* All rights reserved .
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions are met :
*
* 1. Redistributions of source code must retain the above copyright notice , this
* list of conditions and the following disclaimer .
*
* 2. Redistributions in binary form must reproduce the above copyright notice ,
* this list of conditions and the following disclaimer in the documentation
* and / or other materials provided with the distribution .
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS " AS IS "
* AND ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT , INDIRECT , INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL
* DAMAGES ( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES ; LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY ,
* OR TORT ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
*/
# include "DownloadWidget.h"
# include <AK/NumberFormat.h>
# include <AK/SharedBuffer.h>
# include <AK/StringBuilder.h>
# include <LibCore/File.h>
# include <LibCore/StandardPaths.h>
2020-05-26 12:54:58 -04:00
# include <LibDesktop/Launcher.h>
2020-05-05 23:58:22 +02:00
# include <LibGUI/BoxLayout.h>
# include <LibGUI/Button.h>
2020-07-22 15:29:51 +02:00
# include <LibGUI/ImageWidget.h>
2020-05-05 23:58:22 +02:00
# include <LibGUI/Label.h>
2020-05-12 20:30:33 +02:00
# include <LibGUI/MessageBox.h>
2020-05-05 23:58:22 +02:00
# include <LibGUI/ProgressBar.h>
# include <LibGUI/Window.h>
# include <LibProtocol/Client.h>
2020-06-01 20:42:50 +02:00
# include <LibWeb/Loader/ResourceLoader.h>
2020-05-05 23:58:22 +02:00
# include <math.h>
namespace Browser {
DownloadWidget : : DownloadWidget ( const URL & url )
: m_url ( url )
{
{
StringBuilder builder ;
builder . append ( Core : : StandardPaths : : downloads_directory ( ) ) ;
builder . append ( ' / ' ) ;
builder . append ( m_url . basename ( ) ) ;
m_destination_path = builder . to_string ( ) ;
}
m_elapsed_timer . start ( ) ;
m_download = Web : : ResourceLoader : : the ( ) . protocol_client ( ) . start_download ( url . to_string ( ) ) ;
ASSERT ( m_download ) ;
m_download - > on_progress = [ this ] ( Optional < u32 > total_size , u32 downloaded_size ) {
did_progress ( total_size . value ( ) , downloaded_size ) ;
} ;
2020-06-13 22:19:34 +02:00
m_download - > on_finish = [ this ] ( bool success , auto & payload , auto payload_storage , auto & response_headers , auto ) {
2020-05-05 23:58:22 +02:00
did_finish ( success , payload , payload_storage , response_headers ) ;
} ;
set_fill_with_background_color ( true ) ;
auto & layout = set_layout < GUI : : VerticalBoxLayout > ( ) ;
layout . set_margins ( { 4 , 4 , 4 , 4 } ) ;
auto & animation_container = add < GUI : : Widget > ( ) ;
animation_container . set_size_policy ( GUI : : SizePolicy : : Fill , GUI : : SizePolicy : : Fixed ) ;
animation_container . set_preferred_size ( 0 , 32 ) ;
auto & animation_layout = animation_container . set_layout < GUI : : HorizontalBoxLayout > ( ) ;
2020-06-17 21:50:39 +03:00
2020-07-22 15:29:51 +02:00
auto & browser_image = animation_container . add < GUI : : ImageWidget > ( ) ;
2020-06-17 21:50:39 +03:00
browser_image . load_from_file ( " /res/download-animation.gif " ) ;
2020-05-05 23:58:22 +02:00
animation_layout . add_spacer ( ) ;
2020-06-17 21:50:39 +03:00
2020-05-05 23:58:22 +02:00
auto & source_label = add < GUI : : Label > ( String : : format ( " From: %s " , url . to_string ( ) . characters ( ) ) ) ;
source_label . set_text_alignment ( Gfx : : TextAlignment : : CenterLeft ) ;
source_label . set_size_policy ( GUI : : SizePolicy : : Fill , GUI : : SizePolicy : : Fixed ) ;
source_label . set_preferred_size ( 0 , 16 ) ;
m_progress_bar = add < GUI : : ProgressBar > ( ) ;
m_progress_bar - > set_size_policy ( GUI : : SizePolicy : : Fill , GUI : : SizePolicy : : Fixed ) ;
m_progress_bar - > set_preferred_size ( 0 , 20 ) ;
m_progress_label = add < GUI : : Label > ( ) ;
m_progress_label - > set_text_alignment ( Gfx : : TextAlignment : : CenterLeft ) ;
m_progress_label - > set_size_policy ( GUI : : SizePolicy : : Fill , GUI : : SizePolicy : : Fixed ) ;
m_progress_label - > set_preferred_size ( 0 , 16 ) ;
auto & destination_label = add < GUI : : Label > ( String : : format ( " To: %s " , m_destination_path . characters ( ) ) ) ;
destination_label . set_text_alignment ( Gfx : : TextAlignment : : CenterLeft ) ;
destination_label . set_size_policy ( GUI : : SizePolicy : : Fill , GUI : : SizePolicy : : Fixed ) ;
destination_label . set_preferred_size ( 0 , 16 ) ;
auto & button_container = add < GUI : : Widget > ( ) ;
auto & button_container_layout = button_container . set_layout < GUI : : HorizontalBoxLayout > ( ) ;
button_container_layout . add_spacer ( ) ;
m_cancel_button = button_container . add < GUI : : Button > ( " Cancel " ) ;
m_cancel_button - > set_size_policy ( GUI : : SizePolicy : : Fixed , GUI : : SizePolicy : : Fixed ) ;
m_cancel_button - > set_preferred_size ( 100 , 22 ) ;
2020-05-12 20:30:33 +02:00
m_cancel_button - > on_click = [ this ] ( auto ) {
2020-05-05 23:58:22 +02:00
bool success = m_download - > stop ( ) ;
ASSERT ( success ) ;
window ( ) - > close ( ) ;
} ;
m_close_button = button_container . add < GUI : : Button > ( " OK " ) ;
m_close_button - > set_enabled ( false ) ;
m_close_button - > set_size_policy ( GUI : : SizePolicy : : Fixed , GUI : : SizePolicy : : Fixed ) ;
m_close_button - > set_preferred_size ( 100 , 22 ) ;
2020-05-12 20:30:33 +02:00
m_close_button - > on_click = [ this ] ( auto ) {
2020-05-05 23:58:22 +02:00
window ( ) - > close ( ) ;
} ;
}
DownloadWidget : : ~ DownloadWidget ( )
{
}
void DownloadWidget : : did_progress ( Optional < u32 > total_size , u32 downloaded_size )
{
m_progress_bar - > set_min ( 0 ) ;
2020-05-30 22:21:50 +02:00
if ( total_size . has_value ( ) ) {
int percent = roundf ( ( ( float ) downloaded_size / ( float ) total_size . value ( ) ) * 100.0f ) ;
window ( ) - > set_progress ( percent ) ;
2020-05-05 23:58:22 +02:00
m_progress_bar - > set_max ( total_size . value ( ) ) ;
2020-05-30 22:21:50 +02:00
} else {
2020-05-05 23:58:22 +02:00
m_progress_bar - > set_max ( 0 ) ;
2020-05-30 22:21:50 +02:00
}
2020-05-05 23:58:22 +02:00
m_progress_bar - > set_value ( downloaded_size ) ;
{
StringBuilder builder ;
builder . append ( " Downloaded " ) ;
builder . append ( human_readable_size ( downloaded_size ) ) ;
builder . appendf ( " in %d sec " , m_elapsed_timer . elapsed ( ) / 1000 ) ;
m_progress_label - > set_text ( builder . to_string ( ) ) ;
}
{
StringBuilder builder ;
if ( total_size . has_value ( ) ) {
int percent = roundf ( ( ( float ) downloaded_size / ( float ) total_size . value ( ) ) * 100 ) ;
builder . appendf ( " %d%% " , percent ) ;
} else {
builder . append ( human_readable_size ( downloaded_size ) ) ;
}
builder . append ( " of " ) ;
builder . append ( m_url . basename ( ) ) ;
window ( ) - > set_title ( builder . to_string ( ) ) ;
}
}
2020-05-10 21:26:53 +02:00
void DownloadWidget : : did_finish ( bool success , const ByteBuffer & payload , RefPtr < SharedBuffer > payload_storage , const HashMap < String , String , CaseInsensitiveStringTraits > & response_headers )
2020-05-05 23:58:22 +02:00
{
( void ) payload ;
( void ) payload_storage ;
( void ) response_headers ;
dbg ( ) < < " did_finish, success= " < < success ;
2020-05-26 12:54:58 -04:00
2020-05-05 23:58:22 +02:00
m_close_button - > set_enabled ( true ) ;
2020-05-26 12:54:58 -04:00
m_cancel_button - > set_text ( " Open in Folder " ) ;
m_cancel_button - > on_click = [ this ] ( auto ) {
Desktop : : Launcher : : open ( URL : : create_with_file_protocol ( Core : : StandardPaths : : downloads_directory ( ) ) ) ;
window ( ) - > close ( ) ;
} ;
m_cancel_button - > update ( ) ;
2020-05-05 23:58:22 +02:00
if ( ! success ) {
2020-07-15 20:45:11 -06:00
GUI : : MessageBox : : show ( window ( ) , String : : format ( " Download failed for some reason " ) , " Download failed " , GUI : : MessageBox : : Type : : Error ) ;
2020-05-05 23:58:22 +02:00
window ( ) - > close ( ) ;
return ;
}
auto file_or_error = Core : : File : : open ( m_destination_path , Core : : IODevice : : WriteOnly ) ;
if ( file_or_error . is_error ( ) ) {
2020-07-15 20:45:11 -06:00
GUI : : MessageBox : : show ( window ( ) , String : : format ( " Cannot open %s for writing " , m_destination_path . characters ( ) ) , " Download failed " , GUI : : MessageBox : : Type : : Error ) ;
2020-05-05 23:58:22 +02:00
window ( ) - > close ( ) ;
return ;
}
auto & file = * file_or_error . value ( ) ;
bool write_success = file . write ( payload . data ( ) , payload . size ( ) ) ;
ASSERT ( write_success ) ;
}
}