[Settings] 'Check for updates' button behavior changed (#4385)

This commit is contained in:
Seraphima Zykova 2020-06-23 15:53:02 +03:00 committed by GitHub
parent 87f0fcfd52
commit 5c1999b3d0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 460 additions and 87 deletions

View File

@ -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>
@ -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;
}

View File

@ -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()
@ -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{
@ -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);
@ -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);
}

View File

@ -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);
}

View File

@ -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();
}
}

View File

@ -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;
};
}

View File

@ -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));
}
}
}

View File

@ -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);
}
}

View File

@ -2,7 +2,9 @@
#include "version.h"
#include "http_client.h"
#include "updating.h"
#include "toast_notifications_helper.h"
#include <msi.h>
#include <common/common.h>
@ -11,9 +13,6 @@
#include <common/winstore.h>
#include <common/notifications.h>
#include <winrt/Windows.Web.Http.h>
#include <winrt/Windows.Web.Http.Headers.h>
#include <winrt/Windows.Storage.Streams.h>
#include <winrt/Windows.Management.Deployment.h>
#include <winrt/Windows.Networking.Connectivity.h>
@ -23,13 +22,10 @@ namespace
{
const wchar_t POWER_TOYS_UPGRADE_CODE[] = L"{42B84BF7-5FBF-473B-9C8B-049DC16F7708}";
const wchar_t DONT_SHOW_AGAIN_RECORD_REGISTRY_PATH[] = L"delete_previous_powertoys_confirm";
const wchar_t USER_AGENT[] = L"Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)";
const wchar_t LATEST_RELEASE_ENDPOINT[] = L"https://api.github.com/repos/microsoft/PowerToys/releases/latest";
const wchar_t MSIX_PACKAGE_NAME[] = L"Microsoft.PowerToys";
const wchar_t MSIX_PACKAGE_PUBLISHER[] = L"CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US";
const wchar_t UPDATE_NOTIFY_TOAST_TAG[] = L"PTUpdateNotifyTag";
const wchar_t UPDATE_READY_TOAST_TAG[] = L"PTUpdateReadyTag";
const size_t MAX_DOWNLOAD_ATTEMPTS = 3;
}
@ -37,30 +33,10 @@ namespace localized_strings
{
const wchar_t OFFER_UNINSTALL_MSI[] = L"We've detected a previous installation of PowerToys. Would you like to remove it?";
const wchar_t OFFER_UNINSTALL_MSI_TITLE[] = L"PowerToys: uninstall previous version?";
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_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 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_AGREE[] = L"Visit";
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
{
inline winrt::Windows::Web::Http::HttpClient create_http_client()
{
winrt::Windows::Web::Http::HttpClient client;
auto headers = client.DefaultRequestHeaders();
headers.UserAgent().TryParseAdd(USER_AGENT);
return client;
}
std::wstring get_msi_package_path()
{
std::wstring package_path;
@ -93,8 +69,8 @@ namespace updating
return package_path;
}
bool offer_msi_uninstallation()
bool offer_msi_uninstallation()
{
const auto selection = SHMessageBoxCheckW(nullptr, localized_strings::OFFER_UNINSTALL_MSI, localized_strings::OFFER_UNINSTALL_MSI_TITLE, MB_ICONQUESTION | MB_YESNO, IDNO, DONT_SHOW_AGAIN_RECORD_REGISTRY_PATH);
return selection == IDYES;
@ -105,18 +81,18 @@ namespace updating
const auto uninstall_result = MsiInstallProductW(package_path.c_str(), L"REMOVE=ALL");
if (ERROR_SUCCESS == uninstall_result)
{
notifications::show_toast(localized_strings::UNINSTALLATION_SUCCESS);
notifications::show_uninstallation_success();
return true;
}
else if (auto system_message = get_last_error_message(uninstall_result); system_message.has_value())
{
try
{
notifications::show_toast(*system_message);
::notifications::show_toast(*system_message);
}
catch (...)
{
notifications::show_toast(localized_strings::UNINSTALLATION_UNKNOWN_ERROR);
updating::notifications::show_uninstallation_error();
}
}
return false;
@ -126,10 +102,8 @@ namespace updating
{
try
{
auto client = create_http_client();
auto response = co_await client.GetAsync(winrt::Windows::Foundation::Uri{ LATEST_RELEASE_ENDPOINT });
(void)response.EnsureSuccessStatusCode();
const auto body = co_await response.Content().ReadAsStringAsync();
http::HttpClient client;
const auto body = co_await client.request(winrt::Windows::Foundation::Uri{ LATEST_RELEASE_ENDPOINT });
auto json_body = json::JsonValue::Parse(body).GetObjectW();
auto new_version = json_body.GetNamedString(L"tag_name");
winrt::Windows::Foundation::Uri release_page_uri{ json_body.GetNamedString(L"html_url") };
@ -213,16 +187,12 @@ namespace updating
return { std::move(path_str) };
}
std::future<void> try_download_file(const std::filesystem::path& destination, const winrt::Windows::Foundation::Uri& url)
std::filesystem::path create_download_path()
{
namespace storage = winrt::Windows::Storage;
auto client = create_http_client();
auto response = co_await client.GetAsync(url);
(void)response.EnsureSuccessStatusCode();
auto file_stream = co_await storage::Streams::FileRandomAccessStream::OpenAsync(destination.c_str(), storage::FileAccessMode::ReadWrite, storage::StorageOpenOptions::AllowReadersAndWriters, storage::Streams::FileOpenDisposition::CreateAlways);
co_await response.Content().WriteToStreamAsync(file_stream);
file_stream.Close();
auto installer_download_dst = get_pending_updates_path();
std::error_code _;
std::filesystem::create_directories(installer_download_dst, _);
return installer_download_dst;
}
std::future<void> try_autoupdate(const bool download_updates_automatically)
@ -232,24 +202,17 @@ namespace updating
{
co_return;
}
using namespace localized_strings;
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 += new_version->version_string;
if (download_updates_automatically && !could_be_costly_connection())
{
auto installer_download_dst = get_pending_updates_path();
std::error_code _;
std::filesystem::create_directories(installer_download_dst, _);
installer_download_dst /= new_version->installer_filename;
auto installer_download_dst = create_download_path() / new_version->installer_filename;
bool download_success = false;
for (size_t i = 0; i < MAX_DOWNLOAD_ATTEMPTS; ++i)
{
try
{
co_await try_download_file(installer_download_dst, new_version->installer_download_url);
http::HttpClient client;
co_await client.download(new_version->installer_download_url, installer_download_dst);
download_success = true;
break;
}
@ -260,32 +223,56 @@ namespace updating
}
if (!download_success)
{
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;
notifications::show_toast_with_activations(std::move(contents), {}, { notifications::link_button{ GITHUB_NEW_VERSION_AGREE, new_version->release_page_uri.ToString().c_str() } }, std::move(toast_params));
updating::notifications::show_install_error(new_version.value());
co_return;
}
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;
notifications::show_toast_with_activations(std::move(new_version_ready),
{},
{ notifications::link_button{ GITHUB_NEW_VERSION_UPDATE_NOW, L"powertoys://update_now/" + new_version->installer_filename },
notifications::link_button{ GITHUB_NEW_VERSION_UPDATE_AFTER_RESTART, L"powertoys://schedule_update/" + new_version->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));
updating::notifications::show_version_ready(new_version.value());
}
else
{
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;
notifications::show_toast_with_activations(std::move(contents), {}, { notifications::link_button{ GITHUB_NEW_VERSION_AGREE, new_version->release_page_uri.ToString().c_str() } }, std::move(toast_params));
updating::notifications::show_visit_github(new_version.value());
}
}
std::future<void> check_new_version_available()
{
const auto new_version = co_await get_new_github_version_info_async();
if (!new_version)
{
updating::notifications::show_unavailable();
co_return;
}
updating::notifications::show_available(new_version.value());
}
std::future<std::wstring> download_update()
{
const auto new_version = co_await get_new_github_version_info_async();
if (!new_version)
{
co_return L"";
}
auto installer_download_dst = create_download_path() / new_version->installer_filename;
updating::notifications::show_download_start(new_version.value());
try
{
auto progressUpdateHandle = [](float progress) {
updating::notifications::update_download_progress(progress);
};
http::HttpClient client;
co_await client.download(new_version->installer_download_url, installer_download_dst, progressUpdateHandle);
}
catch (...)
{
updating::notifications::show_install_error(new_version.value());
co_return L"";
}
co_return new_version->installer_filename;
}
}

View File

@ -9,8 +9,6 @@
namespace updating
{
std::future<void> try_download_file(const std::filesystem::path& destination, const winrt::Windows::Foundation::Uri& url);
std::wstring get_msi_package_path();
bool uninstall_msi_version(const std::wstring& package_path);
bool offer_msi_uninstallation();
@ -29,5 +27,8 @@ namespace updating
std::future<void> try_autoupdate(const bool download_updates_automatically);
std::filesystem::path get_pending_updates_path();
std::future<void> check_new_version_available();
std::future<std::wstring> download_update();
constexpr inline std::wstring_view installer_filename_pattern = L"powertoyssetup";
}

View File

@ -169,10 +169,14 @@
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="http_client.h" />
<ClInclude Include="toast_notifications_helper.h" />
<ClInclude Include="updating.h" />
<ClInclude Include="pch.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="http_client.cpp" />
<ClCompile Include="toast_notifications_helper.cpp" />
<ClCompile Include="updating.cpp" />
<ClCompile Include="pch.cpp">
<PrecompiledHeader Condition="'$(CIBuild)'!='true'">Create</PrecompiledHeader>

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
@ -21,6 +21,12 @@
<ClInclude Include="updating.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="toast_notifications_helper.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="http_client.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="pch.cpp">
@ -29,6 +35,12 @@
<ClCompile Include="updating.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="toast_notifications_helper.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="http_client.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />

View File

@ -50,6 +50,12 @@ namespace Microsoft.PowerToys.Settings.UI.Runner
System.Windows.Application.Current.Shutdown(); // close application
});
// send IPC Message
shellPage.SetCheckForUpdatesMessageCallback(msg =>
{
Program.GetTwoWayIPCManager().Send(msg);
});
shellPage.SetElevationStatus(Program.IsElevated);
shellPage.SetIsUserAnAdmin(Program.IsUserAnAdmin);
shellPage.Refresh();

View File

@ -352,7 +352,16 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
// callback function to launch the URL to check for updates.
private async void CheckForUpdates_Click()
{
await Launcher.LaunchUriAsync(new Uri("https://github.com/microsoft/PowerToys/releases"));
GeneralSettings settings = SettingsUtils.GetSettings<GeneralSettings>(string.Empty);
settings.CustomActionName = "check_for_updates";
OutGoingGeneralSettings outsettings = new OutGoingGeneralSettings(settings);
GeneralSettingsCustomAction customaction = new GeneralSettingsCustomAction(outsettings);
if (ShellPage.CheckForUpdatesMsgCallback != null)
{
ShellPage.CheckForUpdatesMsgCallback(customaction.ToString());
}
}
public void Restart_Elevated()

View File

@ -33,6 +33,11 @@ namespace Microsoft.PowerToys.Settings.UI.Views
/// </summary>
public static IPCMessageCallback SndRestartAsAdminMsgCallback { get; set; }
/// <summary>
/// Gets or sets iPC callback function for checking updates.
/// </summary>
public static IPCMessageCallback CheckForUpdatesMsgCallback { get; set; }
/// <summary>
/// Gets view model.
/// </summary>
@ -74,6 +79,15 @@ namespace Microsoft.PowerToys.Settings.UI.Views
SndRestartAsAdminMsgCallback = implementation;
}
/// <summary>
/// Set check for updates IPC callback function.
/// </summary>
/// <param name="implementation">delegate function implementation.</param>
public void SetCheckForUpdatesMessageCallback(IPCMessageCallback implementation)
{
CheckForUpdatesMsgCallback = implementation;
}
public void SetElevationStatus(bool isElevated)
{
IsElevated = isElevated;

View File

@ -216,6 +216,7 @@ toast_notification_handler_result toast_notification_handler(const std::wstring_
const std::wstring_view cant_drag_elevated_disable = L"cant_drag_elevated_disable/";
const std::wstring_view update_now = L"update_now/";
const std::wstring_view schedule_update = L"schedule_update/";
const std::wstring_view download_and_install_update = L"download_and_install_update/";
if (param == cant_drag_elevated_disable)
{
@ -240,6 +241,17 @@ toast_notification_handler_result toast_notification_handler(const std::wstring_
return toast_notification_handler_result::exit_success;
}
else if (param.starts_with(download_and_install_update))
{
std::wstring installer_filename = updating::download_update().get();
std::wstring args{ UPDATE_NOW_LAUNCH_STAGE1_CMDARG };
args += L' ';
args += installer_filename;
launch_action_runner(args.c_str());
return toast_notification_handler_result::exit_success;
}
else
{
return toast_notification_handler_result::exit_error;

View File

@ -11,6 +11,7 @@
#include "common/windows_colors.h"
#include "common/common.h"
#include "restart_elevated.h"
#include "update_utils.h"
#include <common/json.h>
#include <common\settings_helpers.cpp>
@ -56,15 +57,32 @@ void dispatch_json_action_to_module(const json::JsonObject& powertoys_configs)
// so it has to be the "restart as (non-)elevated" button.
if (name == L"general")
{
if (is_process_elevated())
try
{
schedule_restart_as_non_elevated();
PostQuitMessage(0);
const auto value = powertoy_element.Value().GetObjectW();
const auto action = value.GetNamedString(L"action_name");
if (action == L"restart_elevation")
{
if (is_process_elevated())
{
schedule_restart_as_non_elevated();
PostQuitMessage(0);
}
else
{
schedule_restart_as_elevated();
PostQuitMessage(0);
}
}
else if (action == L"check_for_updates")
{
std::thread{ [] {
check_for_updates();
} }.detach();
}
}
else
catch (...)
{
schedule_restart_as_elevated();
PostQuitMessage(0);
}
}
else if (modules().find(name) != modules().end())

View File

@ -66,6 +66,18 @@ void github_update_worker()
}
}
void check_for_updates()
{
try
{
updating::check_new_version_available();
}
catch (...)
{
// Couldn't autoupdate
}
}
bool launch_pending_update()
{
try

View File

@ -2,4 +2,5 @@
bool start_msi_uninstallation_sequence();
void github_update_worker();
void check_for_updates();
bool launch_pending_update();