Skip to content

Commit

Permalink
[Settings] 'Check for updates' button behavior changed (#4385)
Browse files Browse the repository at this point in the history
  • Loading branch information
SeraphimaZykova committed Jun 23, 2020
1 parent 87f0fcf commit 5c1999b
Show file tree
Hide file tree
Showing 18 changed files with 460 additions and 87 deletions.
4 changes: 3 additions & 1 deletion src/action_runner/action_runner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#include <common/common.h>
#include <common/updating/updating.h>
#include <common/updating/http_client.h>

#include <winrt/Windows.ApplicationModel.h>
#include <winrt/Windows.Storage.h>
Expand Down Expand Up @@ -164,7 +165,8 @@ bool install_dotnet()
{
try
{
updating::try_download_file(dotnet_download_path, download_link).wait();
http::HttpClient client;
client.download(download_link, dotnet_download_path).wait();
download_success = true;
break;
}
Expand Down
56 changes: 55 additions & 1 deletion src/common/notifications.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ namespace
namespace localized_strings
{
constexpr std::wstring_view SNOOZE_BUTTON = L"Snooze";

constexpr std::wstring_view PT_UPDATE = L"PowerToys update";
constexpr std::wstring_view DOWNLOAD_IN_PROGRESS = L"Downloading...";
constexpr std::wstring_view DOWNLOAD_COMPLETE = L"Download complete";
}

static DWORD loop_thread_id()
Expand Down Expand Up @@ -204,7 +208,19 @@ void notifications::show_toast_with_activations(std::wstring message, std::wstri
toast_xml += title;
toast_xml += L"</text><text>";
toast_xml += message;
toast_xml += L"</text></binding></visual><actions>";
toast_xml += L"</text>";
if (params.progress)
{
toast_xml += LR"(<progress title=")";
toast_xml += localized_strings::PT_UPDATE;
if (params.subtitle)
{
toast_xml += L" ";
toast_xml += *params.subtitle;
}
toast_xml += LR"(" value="{progressValue}" valueStringOverride="{progressValueString}" status="{progressStatus}"/>)";
}
toast_xml += L"</binding></visual><actions>";
for (size_t i = 0; i < size(actions); ++i)
{
std::visit(overloaded{
Expand Down Expand Up @@ -294,6 +310,17 @@ void notifications::show_toast_with_activations(std::wstring message, std::wstri
toast_xml_doc.LoadXml(toast_xml);
ToastNotification notification{ toast_xml_doc };

if (params.progress)
{
float progress = std::clamp(params.progress.value(), 0.0f, 1.0f);
winrt::Windows::Foundation::Collections::StringMap map;
map.Insert(L"progressValue", std::to_wstring(progress));
map.Insert(L"progressValueString", std::to_wstring(static_cast<int>(progress * 100)) + std::wstring(L"%"));
map.Insert(L"progressStatus", localized_strings::DOWNLOAD_IN_PROGRESS);
winrt::Windows::UI::Notifications::NotificationData data(map);
notification.Data(data);
}

const auto notifier = winstore::running_as_packaged() ? ToastNotificationManager::ToastNotificationManager::CreateToastNotifier() :
ToastNotificationManager::ToastNotificationManager::CreateToastNotifier(WIN32_AUMID);

Expand All @@ -315,3 +342,30 @@ void notifications::show_toast_with_activations(std::wstring message, std::wstri

notifier.Show(notification);
}

void notifications::update_progress_bar_toast(std::wstring plaintext_message, toast_params params)
{
if (!params.progress.has_value())
{
return;
}

const auto notifier = winstore::running_as_packaged() ? ToastNotificationManager::ToastNotificationManager::CreateToastNotifier() :
ToastNotificationManager::ToastNotificationManager::CreateToastNotifier(WIN32_AUMID);

float progress = std::clamp(params.progress.value(), 0.0f, 1.0f);
winrt::Windows::Foundation::Collections::StringMap map;
map.Insert(L"progressValue", std::to_wstring(progress));
map.Insert(L"progressValueString", std::to_wstring(static_cast<int>(progress * 100)) + std::wstring(L"%"));
map.Insert(L"progressStatus", progress < 1 ? localized_strings::DOWNLOAD_IN_PROGRESS : localized_strings::DOWNLOAD_COMPLETE);


winrt::Windows::UI::Notifications::NotificationData data(map);
std::wstring tag = L"";
if (params.tag.has_value() && params.tag->length() < 64)
{
tag = *params.tag;
}

winrt::Windows::UI::Notifications::NotificationUpdateResult res = notifier.Update(data, tag);
}
3 changes: 3 additions & 0 deletions src/common/notifications.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,13 @@ namespace notifications
{
std::optional<std::wstring_view> tag;
bool resend_if_scheduled = true;
std::optional<float> progress;
std::optional<std::wstring_view> subtitle;
};

using action_t = std::variant<link_button, background_activated_button, snooze_button>;

void show_toast(std::wstring plaintext_message, toast_params params = {});
void show_toast_with_activations(std::wstring plaintext_message, std::wstring_view background_handler_id, std::vector<action_t> actions, toast_params params = {});
void update_progress_bar_toast(std::wstring plaintext_message, toast_params params);
}
72 changes: 72 additions & 0 deletions src/common/updating/http_client.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#include "pch.h"
#include "http_client.h"

#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Web.Http.Headers.h>
#include <winrt/Windows.Storage.Streams.h>

namespace http
{
using namespace winrt::Windows::Web::Http;
namespace storage = winrt::Windows::Storage;

const wchar_t USER_AGENT[] = L"Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)";

HttpClient::HttpClient()
{
auto headers = m_client.DefaultRequestHeaders();
headers.UserAgent().TryParseAdd(USER_AGENT);
}

std::future<std::wstring> HttpClient::request(const winrt::Windows::Foundation::Uri& url)
{
auto response = co_await m_client.GetAsync(url);
(void)response.EnsureSuccessStatusCode();
auto body = co_await response.Content().ReadAsStringAsync();
co_return std::wstring(body);
}

std::future<void> HttpClient::download(const winrt::Windows::Foundation::Uri& url, const std::wstring& dstFilePath)
{
auto response = co_await m_client.GetAsync(url);
(void)response.EnsureSuccessStatusCode();
auto file_stream = co_await storage::Streams::FileRandomAccessStream::OpenAsync(dstFilePath.c_str(), storage::FileAccessMode::ReadWrite, storage::StorageOpenOptions::AllowReadersAndWriters, storage::Streams::FileOpenDisposition::CreateAlways);
co_await response.Content().WriteToStreamAsync(file_stream);
file_stream.Close();
}

std::future<void> HttpClient::download(const winrt::Windows::Foundation::Uri& url, const std::wstring& dstFilePath, const std::function<void(float)>& progressUpdateCallback)
{
auto response = co_await m_client.GetAsync(url, HttpCompletionOption::ResponseHeadersRead);
response.EnsureSuccessStatusCode();

uint64_t totalBytes = response.Content().Headers().ContentLength().GetUInt64();
auto contentStream = co_await response.Content().ReadAsInputStreamAsync();

uint64_t totalBytesRead = 0;
storage::Streams::Buffer buffer(8192);
auto fileStream = co_await storage::Streams::FileRandomAccessStream::OpenAsync(dstFilePath.c_str(), storage::FileAccessMode::ReadWrite, storage::StorageOpenOptions::AllowReadersAndWriters, storage::Streams::FileOpenDisposition::CreateAlways);

co_await contentStream.ReadAsync(buffer, buffer.Capacity(), storage::Streams::InputStreamOptions::None);
while (buffer.Length() > 0)
{
co_await fileStream.WriteAsync(buffer);
totalBytesRead += buffer.Length();
if (progressUpdateCallback)
{
float percentage = (float)totalBytesRead / totalBytes;
progressUpdateCallback(percentage);
}

co_await contentStream.ReadAsync(buffer, buffer.Capacity(), storage::Streams::InputStreamOptions::None);
}

if (progressUpdateCallback)
{
progressUpdateCallback(1);
}

fileStream.Close();
contentStream.Close();
}
}
19 changes: 19 additions & 0 deletions src/common/updating/http_client.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#pragma once

#include <future>
#include <winrt/Windows.Web.Http.h>

namespace http
{
class HttpClient
{
public:
HttpClient();
std::future<std::wstring> request(const winrt::Windows::Foundation::Uri& url);
std::future<void> download(const winrt::Windows::Foundation::Uri& url, const std::wstring& dstFle);
std::future<void> download(const winrt::Windows::Foundation::Uri& url, const std::wstring& dstFle, const std::function<void(float)>& progressUpdateCallback);

private:
winrt::Windows::Web::Http::HttpClient m_client;
};
}
127 changes: 127 additions & 0 deletions src/common/updating/toast_notifications_helper.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
#include "pch.h"

#include "toast_notifications_helper.h"

#include <common/notifications.h>

#include "updating.h"

#include "VersionHelper.h"
#include "version.h"

namespace
{
const wchar_t UPDATE_NOTIFY_TOAST_TAG[] = L"PTUpdateNotifyTag";
const wchar_t UPDATE_READY_TOAST_TAG[] = L"PTUpdateReadyTag";
}

namespace localized_strings
{
const wchar_t GITHUB_NEW_VERSION_AVAILABLE[] = L"An update to PowerToys is available.\n";
const wchar_t GITHUB_NEW_VERSION_DOWNLOAD_STARTED[] = L"PowerToys download started.\n";
const wchar_t GITHUB_NEW_VERSION_READY_TO_INSTALL[] = L"An update to PowerToys is ready to install.\n";
const wchar_t GITHUB_NEW_VERSION_DOWNLOAD_INSTALL_ERROR[] = L"Error: couldn't download PowerToys installer. Visit our GitHub page to update.\n";
const wchar_t GITHUB_NEW_VERSION_UPDATE_NOW[] = L"Update now";
const wchar_t GITHUB_NEW_VERSION_UPDATE_AFTER_RESTART[] = L"At next launch";

const wchar_t UNINSTALLATION_SUCCESS[] = L"Previous version of PowerToys was uninstalled successfully.";
const wchar_t UNINSTALLATION_UNKNOWN_ERROR[] = L"Error: please uninstall the previous version of PowerToys manually.";

const wchar_t GITHUB_NEW_VERSION_AVAILABLE_OFFER_VISIT[] = L"An update to PowerToys is available. Visit our GitHub page to update.\n";
const wchar_t GITHUB_NEW_VERSION_UNAVAILABLE[] = L"PowerToys is up to date.\n";
const wchar_t GITHUB_NEW_VERSION_VISIT[] = L"Visit";
const wchar_t GITHUB_NEW_VERSION_MORE_INFO[] = L"More info...";
const wchar_t GITHUB_NEW_VERSION_ABORT[] = L"Abort";
const wchar_t GITHUB_NEW_VERSION_SNOOZE_TITLE[] = L"Click Snooze to be reminded in:";
const wchar_t GITHUB_NEW_VERSION_UPDATE_SNOOZE_1D[] = L"1 day";
const wchar_t GITHUB_NEW_VERSION_UPDATE_SNOOZE_5D[] = L"5 days";
}

namespace updating
{
namespace notifications
{
using namespace localized_strings;

std::wstring current_version_to_next_version(const updating::new_version_download_info& info)
{
auto current_version_to_next_version = VersionHelper{ VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION }.toWstring();
current_version_to_next_version += L" -> ";
current_version_to_next_version += info.version_string;
return current_version_to_next_version;
}

void show_unavailable()
{
::notifications::toast_params toast_params{ UPDATE_NOTIFY_TOAST_TAG, false };
std::wstring contents = GITHUB_NEW_VERSION_UNAVAILABLE;
::notifications::show_toast(std::move(contents), std::move(toast_params));
}

void show_available(const updating::new_version_download_info& info)
{
::notifications::toast_params toast_params{ UPDATE_NOTIFY_TOAST_TAG, false };
std::wstring contents = GITHUB_NEW_VERSION_AVAILABLE;
contents += current_version_to_next_version(info);

::notifications::show_toast_with_activations(std::move(contents), {},
{
::notifications::link_button{ GITHUB_NEW_VERSION_UPDATE_NOW, L"powertoys://download_and_install_update/" },
::notifications::link_button{ GITHUB_NEW_VERSION_MORE_INFO, info.release_page_uri.ToString().c_str() }
},
std::move(toast_params));
}

void show_download_start(const updating::new_version_download_info& info)
{
::notifications::toast_params toast_params{ UPDATE_NOTIFY_TOAST_TAG, false, 0.0f, info.version_string };
::notifications::show_toast_with_activations(localized_strings::GITHUB_NEW_VERSION_DOWNLOAD_STARTED, {}, {}, std::move(toast_params));
}

void show_visit_github(const updating::new_version_download_info& info)
{
::notifications::toast_params toast_params{ UPDATE_NOTIFY_TOAST_TAG, false };
std::wstring contents = GITHUB_NEW_VERSION_AVAILABLE_OFFER_VISIT;
contents += current_version_to_next_version(info);
::notifications::show_toast_with_activations(std::move(contents), {}, { ::notifications::link_button{ GITHUB_NEW_VERSION_VISIT, info.release_page_uri.ToString().c_str() } }, std::move(toast_params));
}

void show_install_error(const updating::new_version_download_info& info)
{
::notifications::toast_params toast_params{ UPDATE_NOTIFY_TOAST_TAG, false };
std::wstring contents = GITHUB_NEW_VERSION_DOWNLOAD_INSTALL_ERROR;
contents += current_version_to_next_version(info);
::notifications::show_toast_with_activations(std::move(contents), {}, { ::notifications::link_button{ GITHUB_NEW_VERSION_VISIT, info.release_page_uri.ToString().c_str() } }, std::move(toast_params));
}

void show_version_ready(const updating::new_version_download_info& info)
{
::notifications::toast_params toast_params{ UPDATE_READY_TOAST_TAG, false };
std::wstring new_version_ready{ GITHUB_NEW_VERSION_READY_TO_INSTALL };
new_version_ready += current_version_to_next_version(info);

::notifications::show_toast_with_activations(std::move(new_version_ready),
{},
{ ::notifications::link_button{ GITHUB_NEW_VERSION_UPDATE_NOW, L"powertoys://update_now/" + info.installer_filename },
::notifications::link_button{ GITHUB_NEW_VERSION_UPDATE_AFTER_RESTART, L"powertoys://schedule_update/" + info.installer_filename },
::notifications::snooze_button{ GITHUB_NEW_VERSION_SNOOZE_TITLE, { { GITHUB_NEW_VERSION_UPDATE_SNOOZE_1D, 24 * 60 }, { GITHUB_NEW_VERSION_UPDATE_SNOOZE_5D, 120 * 60 } } } },
std::move(toast_params));
}

void show_uninstallation_success()
{
::notifications::show_toast(localized_strings::UNINSTALLATION_SUCCESS);
}

void show_uninstallation_error()
{
::notifications::show_toast(localized_strings::UNINSTALLATION_UNKNOWN_ERROR);
}

void update_download_progress(float progress)
{
::notifications::toast_params toast_params { UPDATE_NOTIFY_TOAST_TAG, false, progress };
::notifications::update_progress_bar_toast(localized_strings::GITHUB_NEW_VERSION_DOWNLOAD_STARTED, std::move(toast_params));
}
}
}
20 changes: 20 additions & 0 deletions src/common/updating/toast_notifications_helper.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#pragma once

namespace updating
{
struct new_version_download_info;

namespace notifications
{
void show_unavailable();
void show_available(const updating::new_version_download_info& info);
void show_download_start(const updating::new_version_download_info& info);
void show_visit_github(const updating::new_version_download_info& info);
void show_install_error(const updating::new_version_download_info& info);
void show_version_ready(const updating::new_version_download_info& info);
void show_uninstallation_success();
void show_uninstallation_error();

void update_download_progress(float progress);
}
}

0 comments on commit 5c1999b

Please sign in to comment.