mirror of
https://github.com/microsoft/PowerToys.git
synced 2025-06-07 01:08:18 +08:00
[Settings] 'Check for updates' button behavior changed (#4385)
This commit is contained in:
parent
87f0fcfd52
commit
5c1999b3d0
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
src/common/updating/http_client.cpp
Normal file
72
src/common/updating/http_client.cpp
Normal 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();
|
||||
}
|
||||
}
|
19
src/common/updating/http_client.h
Normal file
19
src/common/updating/http_client.h
Normal 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;
|
||||
};
|
||||
}
|
127
src/common/updating/toast_notifications_helper.cpp
Normal file
127
src/common/updating/toast_notifications_helper.cpp
Normal 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));
|
||||
}
|
||||
}
|
||||
}
|
20
src/common/updating/toast_notifications_helper.h
Normal file
20
src/common/updating/toast_notifications_helper.h
Normal 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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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";
|
||||
}
|
@ -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>
|
||||
|
@ -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" />
|
||||
|
@ -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();
|
||||
|
@ -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()
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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())
|
||||
|
@ -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
|
||||
|
@ -2,4 +2,5 @@
|
||||
|
||||
bool start_msi_uninstallation_sequence();
|
||||
void github_update_worker();
|
||||
void check_for_updates();
|
||||
bool launch_pending_update();
|
Loading…
Reference in New Issue
Block a user