diff --git a/README.md b/README.md index 322e5ffc7f..b1eaedead4 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ For a video overview of PowerToys, including install steps and a walkthrough of ### Color Picker -[](https://aka.ms/PowerToysOverview_ColorPicker) [ColorPicker](https://aka.ms/PowerToysOverview_ColorPicker) is a simple and quick system-wide color picker with Win+Shift+C. Color Picker allows to pick colors from any currently running application and automatically copies the HEX or RGB values to your clipboard. This code is based on [Martin Chrzan's Color Picker](https://github.com/martinchrzan/ColorPicker). +[](https://aka.ms/PowerToysOverview_ColorPicker) [Color Picker](https://aka.ms/PowerToysOverview_ColorPicker) is a simple and quick system-wide color picker with Win+Shift+C. Color Picker allows to pick colors from any currently running application and automatically copies the HEX or RGB values to your clipboard. This code is based on [Martin Chrzan's Color Picker](https://github.com/martinchrzan/ColorPicker).


@@ -105,7 +105,7 @@ Download PowerToys from [WinGet](https://github.com/microsoft/winget-cli/release WinGet install powertoys ``` -### Experiential PowerToys utility with Video conference muting +### Experimental PowerToys utility with Video conference muting Install the [pre-release experimental version of PowerToys][github-prerelease-link] to try out this version. It includes all improvements from 0.23 in addition to the Video conference utility. Click on `Assets` to show the files available in the release and then download the .exe installer. diff --git a/installer/PowerToysBootstrapper/bootstrapper/Resources.resx b/installer/PowerToysBootstrapper/bootstrapper/Resources.resx index d1ca376f1a..e80ed5a84a 100644 --- a/installer/PowerToysBootstrapper/bootstrapper/Resources.resx +++ b/installer/PowerToysBootstrapper/bootstrapper/Resources.resx @@ -64,4 +64,94 @@ PowerToys installation error + + An update to PowerToys is available. + + + PowerToys download started. + + + An update to PowerToys is ready to install. + + + Error: couldn't download PowerToys installer. Visit our GitHub page to update. + + + Update now + + + At next launch + + + Error: please uninstall the previous version of PowerToys manually. + + + An update to PowerToys is available. Visit our GitHub page to update. + + + PowerToys is up to date. + + + Visit + + + More info... + + + Abort + + + Click Snooze to be reminded in: + + + 1 day + + + 5 days + + + Downloading... + + + Download complete + + + PowerToys Update + + + We've detected a previous installation of PowerToys. Would you like to remove it? + + + PowerToys: uninstall previous version? + + + Couldn't extract MSI installer! + + + Extracting PowerToys MSI... + + + Uninstalling previous PowerToys version... + + + Couldn't uninstall previous PowerToys version! + + + Installing dotnet... + + + Couldn't install dotnet! + + + Installing new PowerToys version... + + + PowerToys installation complete! + + + Couldn't install new PowerToys version. + + + Snooze + \ No newline at end of file diff --git a/installer/PowerToysBootstrapper/bootstrapper/bootstrapper.cpp b/installer/PowerToysBootstrapper/bootstrapper/bootstrapper.cpp index 2ab0c29cd5..85774cc741 100644 --- a/installer/PowerToysBootstrapper/bootstrapper/bootstrapper.cpp +++ b/installer/PowerToysBootstrapper/bootstrapper/bootstrapper.cpp @@ -14,11 +14,14 @@ extern "C" IMAGE_DOS_HEADER __ImageBase; +auto Strings = updating::notifications::strings::create(); + #define STR_HELPER(x) #x #define STR(x) STR_HELPER(x) -namespace +namespace // Strings in this namespace should not be localized { const wchar_t APPLICATION_ID[] = L"PowerToysInstaller"; + const wchar_t INSTALLATION_TOAST_TITLE[] = L"PowerToys Installation"; const wchar_t TOAST_TAG[] = L"PowerToysInstallerProgress"; const char LOG_FILENAME[] = "powertoys-bootstrapper-" STR(VERSION_MAJOR) "." STR(VERSION_MINOR) "." STR(VERSION_REVISION) ".log"; const char MSI_LOG_FILENAME[] = "powertoys-bootstrapper-msi-" STR(VERSION_MAJOR) "." STR(VERSION_MINOR) "." STR(VERSION_REVISION) ".log"; @@ -27,20 +30,6 @@ namespace #undef STR #undef STR_HELPER -namespace localized_strings -{ - const wchar_t INSTALLER_EXTRACT_ERROR[] = L"Couldn't extract MSI installer!"; - const wchar_t TOAST_TITLE[] = L"PowerToys Installation"; - const wchar_t EXTRACTING_INSTALLER[] = L"Extracting PowerToys MSI..."; - const wchar_t UNINSTALLING_PREVIOUS_VERSION[] = L"Uninstalling previous PowerToys version..."; - const wchar_t UNINSTALL_PREVIOUS_VERSION_ERROR[] = L"Couldn't uninstall previous PowerToys version!"; - const wchar_t INSTALLING_DOTNET[] = L"Installing dotnet..."; - const wchar_t DOTNET_INSTALL_ERROR[] = L"Couldn't install dotnet!"; - const wchar_t INSTALLING_NEW_VERSION[] = L"Installing new PowerToys version..."; - const wchar_t NEW_VERSION_INSTALLATION_DONE[] = L"PowerToys installation complete!"; - const wchar_t NEW_VERSION_INSTALLATION_ERROR[] = L"Couldn't install new PowerToys version."; -} - namespace fs = std::filesystem; std::optional extractEmbeddedInstaller() @@ -96,7 +85,6 @@ void setup_log(fs::path directory, const spdlog::level::level_enum severity) int bootstrapper() { - using namespace localized_strings; winrt::init_apartment(); cxxopts::Options options{ "PowerToysBootstrapper" }; // clang-format off @@ -252,7 +240,7 @@ int bootstrapper() iconPath = std::move(*extractedIcon); } spdlog::debug("Registering app id for toast notifications"); - notifications::register_application_id(TOAST_TITLE, iconPath.c_str()); + notifications::register_application_id(INSTALLATION_TOAST_TITLE, iconPath.c_str()); auto removeShortcut = wil::scope_exit([&] { notifications::unregister_application_id(); @@ -274,12 +262,12 @@ int bootstrapper() std::mutex progressLock; notifications::progress_bar_params progressParams; progressParams.progress = 0.0f; - progressParams.progress_title = EXTRACTING_INSTALLER; + progressParams.progress_title = GET_RESOURCE_STRING(IDS_EXTRACTING_INSTALLER); notifications::toast_params params{ TOAST_TAG, false, std::move(progressParams) }; if (!silent) { spdlog::debug("Launching progress toast notification"); - notifications::show_toast_with_activations({}, TOAST_TITLE, {}, {}, std::move(params)); + notifications::show_toast_with_activations({}, INSTALLATION_TOAST_TITLE, {}, {}, std::move(params)); } auto processToasts = wil::scope_exit([&] { @@ -322,7 +310,7 @@ int bootstrapper() { if (!silent) { - notifications::show_toast(INSTALLER_EXTRACT_ERROR, TOAST_TITLE); + notifications::show_toast(GET_RESOURCE_STRING(IDS_INSTALLER_EXTRACT_ERROR), INSTALLATION_TOAST_TITLE); } spdlog::error("Couldn't install the MSI installer ({})", GetLastError()); return 1; @@ -332,7 +320,7 @@ int bootstrapper() fs::remove(*installerPath, _); }); - updateProgressBar(.25f, UNINSTALLING_PREVIOUS_VERSION); + updateProgressBar(.25f, GET_RESOURCE_STRING(IDS_UNINSTALLING_PREVIOUS_VERSION).c_str()); spdlog::debug("Acquiring existing MSI package path"); const auto package_path = updating::get_msi_package_path(); if (!package_path.empty()) @@ -343,15 +331,15 @@ int bootstrapper() { spdlog::debug("Existing MSI package path not found"); } - if (!package_path.empty() && !updating::uninstall_msi_version(package_path) && !silent) + if (!package_path.empty() && !updating::uninstall_msi_version(package_path, Strings) && !silent) { spdlog::error("Couldn't install the existing MSI package ({})", GetLastError()); - notifications::show_toast(UNINSTALL_PREVIOUS_VERSION_ERROR, TOAST_TITLE); + notifications::show_toast(GET_RESOURCE_STRING(IDS_UNINSTALL_PREVIOUS_VERSION_ERROR), INSTALLATION_TOAST_TITLE); } const bool installDotnet = !skipDotnetInstall; if (installDotnet) { - updateProgressBar(.5f, INSTALLING_DOTNET); + updateProgressBar(.5f, GET_RESOURCE_STRING(IDS_INSTALLING_DOTNET).c_str()); } try @@ -365,7 +353,7 @@ int bootstrapper() !updating::install_dotnet(silent) && !silent) { - notifications::show_toast(DOTNET_INSTALL_ERROR, TOAST_TITLE); + notifications::show_toast(GET_RESOURCE_STRING(IDS_DOTNET_INSTALL_ERROR), INSTALLATION_TOAST_TITLE); } } } @@ -375,13 +363,14 @@ int bootstrapper() MessageBoxW(nullptr, L".NET Core installation", L"Unknown exception encountered!", MB_OK | MB_ICONERROR); } - updateProgressBar(.75f, INSTALLING_NEW_VERSION); + updateProgressBar(.75f, GET_RESOURCE_STRING(IDS_INSTALLING_NEW_VERSION).c_str()); // Always skip dotnet install, because we should've installed it from here earlier std::wstring msiProps = L"SKIPDOTNETINSTALL=1 "; spdlog::debug("Launching MSI installation for new package {}", installerPath->string()); const bool installationDone = MsiInstallProductW(installerPath->c_str(), msiProps.c_str()) == ERROR_SUCCESS; - updateProgressBar(1.f, installationDone ? NEW_VERSION_INSTALLATION_DONE : NEW_VERSION_INSTALLATION_ERROR); + updateProgressBar(1.f, + installationDone ? GET_RESOURCE_STRING(IDS_NEW_VERSION_INSTALLATION_DONE).c_str() : GET_RESOURCE_STRING(IDS_NEW_VERSION_INSTALLATION_ERROR).c_str()); if (!installationDone) { spdlog::error("Couldn't install new MSI package ({})", GetLastError()); diff --git a/installer/PowerToysBootstrapper/bootstrapper/loc/cs/installer/PowerToysBootstrapper/bootstrapper/Resources.resx.lcl b/installer/PowerToysBootstrapper/bootstrapper/loc/cs/installer/PowerToysBootstrapper/bootstrapper/Resources.resx.lcl index 806af68f3a..6bcc4709de 100644 --- a/installer/PowerToysBootstrapper/bootstrapper/loc/cs/installer/PowerToysBootstrapper/bootstrapper/Resources.resx.lcl +++ b/installer/PowerToysBootstrapper/bootstrapper/loc/cs/installer/PowerToysBootstrapper/bootstrapper/Resources.resx.lcl @@ -13,12 +13,18 @@ + + + + + + diff --git a/installer/PowerToysBootstrapper/bootstrapper/loc/de/installer/PowerToysBootstrapper/bootstrapper/Resources.resx.lcl b/installer/PowerToysBootstrapper/bootstrapper/loc/de/installer/PowerToysBootstrapper/bootstrapper/Resources.resx.lcl index 125d416730..0ceb815e69 100644 --- a/installer/PowerToysBootstrapper/bootstrapper/loc/de/installer/PowerToysBootstrapper/bootstrapper/Resources.resx.lcl +++ b/installer/PowerToysBootstrapper/bootstrapper/loc/de/installer/PowerToysBootstrapper/bootstrapper/Resources.resx.lcl @@ -13,12 +13,18 @@ + + + + + + diff --git a/installer/PowerToysBootstrapper/bootstrapper/loc/es/installer/PowerToysBootstrapper/bootstrapper/Resources.resx.lcl b/installer/PowerToysBootstrapper/bootstrapper/loc/es/installer/PowerToysBootstrapper/bootstrapper/Resources.resx.lcl index 74588a0bf4..5f8875c61d 100644 --- a/installer/PowerToysBootstrapper/bootstrapper/loc/es/installer/PowerToysBootstrapper/bootstrapper/Resources.resx.lcl +++ b/installer/PowerToysBootstrapper/bootstrapper/loc/es/installer/PowerToysBootstrapper/bootstrapper/Resources.resx.lcl @@ -13,12 +13,18 @@ + + + + + + diff --git a/installer/PowerToysBootstrapper/bootstrapper/loc/fr/installer/PowerToysBootstrapper/bootstrapper/Resources.resx.lcl b/installer/PowerToysBootstrapper/bootstrapper/loc/fr/installer/PowerToysBootstrapper/bootstrapper/Resources.resx.lcl index fb70b6e461..68c63c6898 100644 --- a/installer/PowerToysBootstrapper/bootstrapper/loc/fr/installer/PowerToysBootstrapper/bootstrapper/Resources.resx.lcl +++ b/installer/PowerToysBootstrapper/bootstrapper/loc/fr/installer/PowerToysBootstrapper/bootstrapper/Resources.resx.lcl @@ -13,12 +13,18 @@ + + + + + + diff --git a/installer/PowerToysBootstrapper/bootstrapper/loc/hu/installer/PowerToysBootstrapper/bootstrapper/Resources.resx.lcl b/installer/PowerToysBootstrapper/bootstrapper/loc/hu/installer/PowerToysBootstrapper/bootstrapper/Resources.resx.lcl index 47eb8d05a1..170a038827 100644 --- a/installer/PowerToysBootstrapper/bootstrapper/loc/hu/installer/PowerToysBootstrapper/bootstrapper/Resources.resx.lcl +++ b/installer/PowerToysBootstrapper/bootstrapper/loc/hu/installer/PowerToysBootstrapper/bootstrapper/Resources.resx.lcl @@ -13,12 +13,18 @@ + + + + + + diff --git a/installer/PowerToysBootstrapper/bootstrapper/loc/ja/installer/PowerToysBootstrapper/bootstrapper/Resources.resx.lcl b/installer/PowerToysBootstrapper/bootstrapper/loc/ja/installer/PowerToysBootstrapper/bootstrapper/Resources.resx.lcl index e72715f337..0ea663700a 100644 --- a/installer/PowerToysBootstrapper/bootstrapper/loc/ja/installer/PowerToysBootstrapper/bootstrapper/Resources.resx.lcl +++ b/installer/PowerToysBootstrapper/bootstrapper/loc/ja/installer/PowerToysBootstrapper/bootstrapper/Resources.resx.lcl @@ -13,12 +13,18 @@ + + + + + + diff --git a/installer/PowerToysBootstrapper/bootstrapper/loc/nl/installer/PowerToysBootstrapper/bootstrapper/Resources.resx.lcl b/installer/PowerToysBootstrapper/bootstrapper/loc/nl/installer/PowerToysBootstrapper/bootstrapper/Resources.resx.lcl index 5a2c84c762..732cf16cab 100644 --- a/installer/PowerToysBootstrapper/bootstrapper/loc/nl/installer/PowerToysBootstrapper/bootstrapper/Resources.resx.lcl +++ b/installer/PowerToysBootstrapper/bootstrapper/loc/nl/installer/PowerToysBootstrapper/bootstrapper/Resources.resx.lcl @@ -13,12 +13,18 @@ + + + + + + diff --git a/installer/PowerToysBootstrapper/bootstrapper/loc/pt-BR/installer/PowerToysBootstrapper/bootstrapper/Resources.resx.lcl b/installer/PowerToysBootstrapper/bootstrapper/loc/pt-BR/installer/PowerToysBootstrapper/bootstrapper/Resources.resx.lcl index 1ca19d3324..e34f883dce 100644 --- a/installer/PowerToysBootstrapper/bootstrapper/loc/pt-BR/installer/PowerToysBootstrapper/bootstrapper/Resources.resx.lcl +++ b/installer/PowerToysBootstrapper/bootstrapper/loc/pt-BR/installer/PowerToysBootstrapper/bootstrapper/Resources.resx.lcl @@ -13,12 +13,18 @@ + + + + + + diff --git a/installer/PowerToysBootstrapper/bootstrapper/loc/ru/installer/PowerToysBootstrapper/bootstrapper/Resources.resx.lcl b/installer/PowerToysBootstrapper/bootstrapper/loc/ru/installer/PowerToysBootstrapper/bootstrapper/Resources.resx.lcl index 03c917be3f..841505881b 100644 --- a/installer/PowerToysBootstrapper/bootstrapper/loc/ru/installer/PowerToysBootstrapper/bootstrapper/Resources.resx.lcl +++ b/installer/PowerToysBootstrapper/bootstrapper/loc/ru/installer/PowerToysBootstrapper/bootstrapper/Resources.resx.lcl @@ -13,12 +13,18 @@ + + + + + + diff --git a/installer/PowerToysBootstrapper/bootstrapper/loc/sv/installer/PowerToysBootstrapper/bootstrapper/Resources.resx.lcl b/installer/PowerToysBootstrapper/bootstrapper/loc/sv/installer/PowerToysBootstrapper/bootstrapper/Resources.resx.lcl index a66e6cb92e..506e8580a1 100644 --- a/installer/PowerToysBootstrapper/bootstrapper/loc/sv/installer/PowerToysBootstrapper/bootstrapper/Resources.resx.lcl +++ b/installer/PowerToysBootstrapper/bootstrapper/loc/sv/installer/PowerToysBootstrapper/bootstrapper/Resources.resx.lcl @@ -13,12 +13,18 @@ + + + + + + diff --git a/installer/PowerToysBootstrapper/bootstrapper/loc/tr/installer/PowerToysBootstrapper/bootstrapper/Resources.resx.lcl b/installer/PowerToysBootstrapper/bootstrapper/loc/tr/installer/PowerToysBootstrapper/bootstrapper/Resources.resx.lcl index c10bb57c10..c80fbc0db4 100644 --- a/installer/PowerToysBootstrapper/bootstrapper/loc/tr/installer/PowerToysBootstrapper/bootstrapper/Resources.resx.lcl +++ b/installer/PowerToysBootstrapper/bootstrapper/loc/tr/installer/PowerToysBootstrapper/bootstrapper/Resources.resx.lcl @@ -13,12 +13,18 @@ + + + + + + diff --git a/installer/PowerToysBootstrapper/bootstrapper/loc/zh-Hans/installer/PowerToysBootstrapper/bootstrapper/Resources.resx.lcl b/installer/PowerToysBootstrapper/bootstrapper/loc/zh-Hans/installer/PowerToysBootstrapper/bootstrapper/Resources.resx.lcl index ee330663f3..a1d18ae8d6 100644 --- a/installer/PowerToysBootstrapper/bootstrapper/loc/zh-Hans/installer/PowerToysBootstrapper/bootstrapper/Resources.resx.lcl +++ b/installer/PowerToysBootstrapper/bootstrapper/loc/zh-Hans/installer/PowerToysBootstrapper/bootstrapper/Resources.resx.lcl @@ -13,12 +13,18 @@ + + + + + + diff --git a/installer/PowerToysSetup/Product.wxs b/installer/PowerToysSetup/Product.wxs index fa36e6b81a..74307b7181 100644 --- a/installer/PowerToysSetup/Product.wxs +++ b/installer/PowerToysSetup/Product.wxs @@ -883,7 +883,7 @@ - + diff --git a/src/action_runner/Resources.resx b/src/action_runner/Resources.resx index d1ca376f1a..1b90cd3d36 100644 --- a/src/action_runner/Resources.resx +++ b/src/action_runner/Resources.resx @@ -64,4 +64,67 @@ PowerToys installation error + + An update to PowerToys is available. + + + PowerToys download started. + + + An update to PowerToys is ready to install. + + + Error: couldn't download PowerToys installer. Visit our GitHub page to update. + + + Update now + + + At next launch + + + Error: please uninstall the previous version of PowerToys manually. + + + An update to PowerToys is available. Visit our GitHub page to update. + + + PowerToys is up to date. + + + Visit + + + More info... + + + Abort + + + Click Snooze to be reminded in: + + + 1 day + + + 5 days + + + Downloading... + + + Download complete + + + PowerToys Update + + + We've detected a previous installation of PowerToys. Would you like to remove it? + + + PowerToys: uninstall previous version? + + + Snooze + \ No newline at end of file diff --git a/src/action_runner/action_runner.cpp b/src/action_runner/action_runner.cpp index acabf8d767..321be922b2 100644 --- a/src/action_runner/action_runner.cpp +++ b/src/action_runner/action_runner.cpp @@ -1,4 +1,6 @@ #define WIN32_LEAN_AND_MEAN +#include "Generated Files/resource.h" + #include #include @@ -16,10 +18,10 @@ #include "../runner/tray_icon.h" #include "../runner/action_runner_utils.h" -#include "Generated Files/resource.h" - extern "C" IMAGE_DOS_HEADER __ImageBase; +auto Strings = updating::notifications::strings::create(); + int uninstall_msi_action() { const auto package_path = updating::get_msi_package_path(); @@ -27,7 +29,7 @@ int uninstall_msi_action() { return 0; } - if (!updating::uninstall_msi_version(package_path)) + if (!updating::uninstall_msi_version(package_path, Strings)) { return -1; } diff --git a/src/action_runner/loc/cs/src/runner/Resources.resx.lcl b/src/action_runner/loc/cs/src/runner/Resources.resx.lcl index 4dec18f832..f6d43d2ad5 100644 --- a/src/action_runner/loc/cs/src/runner/Resources.resx.lcl +++ b/src/action_runner/loc/cs/src/runner/Resources.resx.lcl @@ -13,30 +13,45 @@ + + + + + + + + + + + + + + + diff --git a/src/action_runner/loc/de/src/runner/Resources.resx.lcl b/src/action_runner/loc/de/src/runner/Resources.resx.lcl index 5b8e0e52b3..7424804ed1 100644 --- a/src/action_runner/loc/de/src/runner/Resources.resx.lcl +++ b/src/action_runner/loc/de/src/runner/Resources.resx.lcl @@ -13,30 +13,45 @@ + + + + + + + + + + + + + + + diff --git a/src/action_runner/loc/es/src/runner/Resources.resx.lcl b/src/action_runner/loc/es/src/runner/Resources.resx.lcl index 8150491f92..3ced2ecaff 100644 --- a/src/action_runner/loc/es/src/runner/Resources.resx.lcl +++ b/src/action_runner/loc/es/src/runner/Resources.resx.lcl @@ -13,30 +13,45 @@ + + + + + + + + + + + + + + + diff --git a/src/action_runner/loc/fr/src/runner/Resources.resx.lcl b/src/action_runner/loc/fr/src/runner/Resources.resx.lcl index 6a6ad56295..2674cc5036 100644 --- a/src/action_runner/loc/fr/src/runner/Resources.resx.lcl +++ b/src/action_runner/loc/fr/src/runner/Resources.resx.lcl @@ -13,30 +13,45 @@ + + + + + + + + + + + + + + + diff --git a/src/action_runner/loc/hu/src/runner/Resources.resx.lcl b/src/action_runner/loc/hu/src/runner/Resources.resx.lcl index 2d1197d4a7..18f1420373 100644 --- a/src/action_runner/loc/hu/src/runner/Resources.resx.lcl +++ b/src/action_runner/loc/hu/src/runner/Resources.resx.lcl @@ -13,30 +13,45 @@ + + + + + + + + + + + + + + + diff --git a/src/action_runner/loc/ja/src/runner/Resources.resx.lcl b/src/action_runner/loc/ja/src/runner/Resources.resx.lcl index 95e71485cd..f8c5716a14 100644 --- a/src/action_runner/loc/ja/src/runner/Resources.resx.lcl +++ b/src/action_runner/loc/ja/src/runner/Resources.resx.lcl @@ -13,30 +13,45 @@ + + + + + + + + + + + + + + + diff --git a/src/action_runner/loc/nl/src/runner/Resources.resx.lcl b/src/action_runner/loc/nl/src/runner/Resources.resx.lcl index 062cf9bdaa..80862face2 100644 --- a/src/action_runner/loc/nl/src/runner/Resources.resx.lcl +++ b/src/action_runner/loc/nl/src/runner/Resources.resx.lcl @@ -13,30 +13,45 @@ + + + + + + + + + + + + + + + diff --git a/src/action_runner/loc/pt-BR/src/runner/Resources.resx.lcl b/src/action_runner/loc/pt-BR/src/runner/Resources.resx.lcl index 32f7bcdbee..ec55d333e5 100644 --- a/src/action_runner/loc/pt-BR/src/runner/Resources.resx.lcl +++ b/src/action_runner/loc/pt-BR/src/runner/Resources.resx.lcl @@ -13,30 +13,45 @@ + + + + + + + + + + + + + + + diff --git a/src/action_runner/loc/ru/src/runner/Resources.resx.lcl b/src/action_runner/loc/ru/src/runner/Resources.resx.lcl index 45350da9a6..9c5febc6f5 100644 --- a/src/action_runner/loc/ru/src/runner/Resources.resx.lcl +++ b/src/action_runner/loc/ru/src/runner/Resources.resx.lcl @@ -13,30 +13,45 @@ + + + + + + + + + + + + + + + diff --git a/src/action_runner/loc/tr/src/runner/Resources.resx.lcl b/src/action_runner/loc/tr/src/runner/Resources.resx.lcl index dcb2988a86..4dc1589b9d 100644 --- a/src/action_runner/loc/tr/src/runner/Resources.resx.lcl +++ b/src/action_runner/loc/tr/src/runner/Resources.resx.lcl @@ -13,30 +13,45 @@ + + + + + + + + + + + + + + + diff --git a/src/action_runner/loc/zh-Hans/src/runner/Resources.resx.lcl b/src/action_runner/loc/zh-Hans/src/runner/Resources.resx.lcl index a905f2d967..6443430967 100644 --- a/src/action_runner/loc/zh-Hans/src/runner/Resources.resx.lcl +++ b/src/action_runner/loc/zh-Hans/src/runner/Resources.resx.lcl @@ -13,30 +13,45 @@ + + + + + + + + + + + + + + + diff --git a/src/common/common.cpp b/src/common/common.cpp index 8d9d251e72..2c7d3e919d 100644 --- a/src/common/common.cpp +++ b/src/common/common.cpp @@ -85,22 +85,22 @@ std::optional get_last_error_message(const DWORD dw) return message; } -void show_last_error_message(LPCWSTR lpszFunction, DWORD dw, LPCWSTR errorTitle) +void show_last_error_message(LPCWSTR functionName, DWORD dw, LPCWSTR errorTitle) { const auto system_message = get_last_error_message(dw); if (!system_message.has_value()) { return; } - LPWSTR lpDisplayBuf = (LPWSTR)LocalAlloc(LMEM_ZEROINIT, (system_message->size() + lstrlenW(lpszFunction) + 40) * sizeof(WCHAR)); + LPWSTR lpDisplayBuf = (LPWSTR)LocalAlloc(LMEM_ZEROINIT, (system_message->size() + lstrlenW(functionName) + 40) * sizeof(WCHAR)); if (lpDisplayBuf != NULL) { StringCchPrintfW(lpDisplayBuf, LocalSize(lpDisplayBuf) / sizeof(WCHAR), - localized_strings::LAST_ERROR_FORMAT_STRING, - lpszFunction, - dw, - system_message->c_str()); + L"%s: %s (%d)", + functionName, + system_message->c_str(), + dw); MessageBoxW(NULL, (LPCTSTR)lpDisplayBuf, errorTitle, MB_OK | MB_ICONERROR); LocalFree(lpDisplayBuf); } diff --git a/src/common/common.h b/src/common/common.h index e826702a7b..ed3db9e0a4 100644 --- a/src/common/common.h +++ b/src/common/common.h @@ -7,12 +7,6 @@ #include -namespace localized_strings -{ - const wchar_t LAST_ERROR_FORMAT_STRING[] = L"%s failed with error %d: %s"; - const wchar_t LAST_ERROR_TITLE_STRING[] = L"Error"; -} - // Gets position of given window. std::optional get_window_pos(HWND hwnd); @@ -23,7 +17,7 @@ bool is_system_window(HWND hwnd, const char* class_name); int run_message_loop(const bool until_idle = false, const std::optional timeout_seconds = {}); std::optional get_last_error_message(const DWORD dw); -void show_last_error_message(LPCWSTR lpszFunction, DWORD dw, LPCWSTR errorTitle = localized_strings::LAST_ERROR_TITLE_STRING); +void show_last_error_message(LPCWSTR lpszFunction, DWORD dw, LPCWSTR errorTitle); enum WindowState { diff --git a/src/common/notifications.cpp b/src/common/notifications.cpp index f87064b4cd..bb48d76feb 100644 --- a/src/common/notifications.cpp +++ b/src/common/notifications.cpp @@ -33,8 +33,7 @@ using winrt::Windows::UI::Notifications::ToastNotificationManager; namespace fs = std::filesystem; -// This namespace contains strings that SHOULD NOT be localized -namespace +namespace // Strings in this namespace should not be localized { constexpr std::wstring_view TASK_NAME = L"PowerToysBackgroundNotificationsHandler"; constexpr std::wstring_view TASK_ENTRYPOINT = L"PowerToysNotifications.BackgroundHandler"; @@ -45,11 +44,6 @@ namespace constexpr std::wstring_view DEFAULT_TOAST_GROUP = L"PowerToysToastTag"; } -namespace localized_strings -{ - constexpr std::wstring_view SNOOZE_BUTTON = L"Snooze"; -} - static DWORD loop_thread_id() { static const DWORD thread_id = GetCurrentThreadId(); @@ -365,7 +359,7 @@ void notifications::show_toast_with_activations(std::wstring message, toast_xml += '"'; } toast_xml += LR"( content=")"; - toast_xml += localized_strings::SNOOZE_BUTTON; + toast_xml += b.snooze_button_title; toast_xml += LR"(" />)"; } }, actions[i]); diff --git a/src/common/notifications.h b/src/common/notifications.h index ac52539b4f..01a0a986e0 100644 --- a/src/common/notifications.h +++ b/src/common/notifications.h @@ -28,6 +28,7 @@ namespace notifications { std::wstring snooze_title; std::vector durations; + std::wstring snooze_button_title; }; struct link_button @@ -45,7 +46,7 @@ namespace notifications struct progress_bar_params { - std::wstring_view progress_title; + std::wstring progress_title; float progress = 0.f; }; diff --git a/src/common/updating/notifications.cpp b/src/common/updating/notifications.cpp index 8984df265f..01e523e657 100644 --- a/src/common/updating/notifications.cpp +++ b/src/common/updating/notifications.cpp @@ -9,39 +9,10 @@ #include "VersionHelper.h" #include "version.h" -namespace -{ - const wchar_t TOAST_TITLE[] = L"PowerToys Update"; -} - -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_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"; - const wchar_t DOWNLOAD_IN_PROGRESS[] = L"Downloading..."; - const wchar_t DOWNLOAD_COMPLETE[] = L"Download complete"; -} - namespace updating { namespace notifications { - using namespace localized_strings; using namespace ::notifications; std::wstring current_version_to_next_version(const updating::new_version_download_info& info) { @@ -51,108 +22,123 @@ namespace updating return current_version_to_next_version; } - void show_unavailable() + void show_unavailable(const notifications::strings& strings) { remove_toasts(UPDATING_PROCESS_TOAST_TAG); toast_params toast_params{ UPDATING_PROCESS_TOAST_TAG, false }; - std::wstring contents = GITHUB_NEW_VERSION_UNAVAILABLE; - show_toast(std::move(contents), TOAST_TITLE, std::move(toast_params)); + std::wstring contents = strings.GITHUB_NEW_VERSION_UNAVAILABLE; + show_toast(std::move(contents), strings.TOAST_TITLE, std::move(toast_params)); } - void show_available(const updating::new_version_download_info& info) + void show_available(const updating::new_version_download_info& info, const notifications::strings& strings) { remove_toasts(UPDATING_PROCESS_TOAST_TAG); toast_params toast_params{ UPDATING_PROCESS_TOAST_TAG, false }; - std::wstring contents = GITHUB_NEW_VERSION_AVAILABLE; + std::wstring contents = strings.GITHUB_NEW_VERSION_AVAILABLE; + contents += L'\n'; contents += current_version_to_next_version(info); show_toast_with_activations(std::move(contents), - TOAST_TITLE, + strings.TOAST_TITLE, {}, - { link_button{ GITHUB_NEW_VERSION_UPDATE_NOW, L"powertoys://download_and_install_update/" }, link_button{ GITHUB_NEW_VERSION_MORE_INFO, info.release_page_uri.ToString().c_str() } }, + { link_button{ strings.GITHUB_NEW_VERSION_UPDATE_NOW, + L"powertoys://download_and_install_update/" }, + link_button{ strings.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) + void show_download_start(const updating::new_version_download_info& info, const notifications::strings& strings) { remove_toasts(UPDATING_PROCESS_TOAST_TAG); progress_bar_params progress_bar_params; std::wstring progress_title{ info.version_string }; progress_title += L' '; - progress_title += localized_strings::DOWNLOAD_IN_PROGRESS; + progress_title += strings.DOWNLOAD_IN_PROGRESS; progress_bar_params.progress_title = progress_title; progress_bar_params.progress = .0f; toast_params toast_params{ UPDATING_PROCESS_TOAST_TAG, false, std::move(progress_bar_params) }; - show_toast_with_activations(localized_strings::GITHUB_NEW_VERSION_DOWNLOAD_STARTED, - TOAST_TITLE, + show_toast_with_activations(strings.GITHUB_NEW_VERSION_DOWNLOAD_STARTED, + strings.TOAST_TITLE, {}, {}, std::move(toast_params)); } - void show_visit_github(const updating::new_version_download_info& info) + void show_visit_github(const updating::new_version_download_info& info, const notifications::strings& strings) { remove_toasts(UPDATING_PROCESS_TOAST_TAG); toast_params toast_params{ UPDATING_PROCESS_TOAST_TAG, false }; - std::wstring contents = GITHUB_NEW_VERSION_AVAILABLE_OFFER_VISIT; + std::wstring contents = strings.GITHUB_NEW_VERSION_AVAILABLE_OFFER_VISIT; + contents += L'\n'; contents += current_version_to_next_version(info); show_toast_with_activations(std::move(contents), - TOAST_TITLE, + strings.TOAST_TITLE, {}, - { link_button{ GITHUB_NEW_VERSION_VISIT, info.release_page_uri.ToString().c_str() } }, + { link_button{ strings.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) + void show_install_error(const updating::new_version_download_info& info, const notifications::strings& strings) { remove_toasts(UPDATING_PROCESS_TOAST_TAG); toast_params toast_params{ UPDATING_PROCESS_TOAST_TAG, false }; - std::wstring contents = GITHUB_NEW_VERSION_DOWNLOAD_INSTALL_ERROR; + std::wstring contents = strings.GITHUB_NEW_VERSION_DOWNLOAD_INSTALL_ERROR; + contents += L'\n'; contents += current_version_to_next_version(info); show_toast_with_activations(std::move(contents), - TOAST_TITLE, + strings.TOAST_TITLE, {}, - { link_button{ GITHUB_NEW_VERSION_VISIT, info.release_page_uri.ToString().c_str() } }, + { link_button{ strings.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) + void show_version_ready(const updating::new_version_download_info& info, const notifications::strings& strings) { remove_toasts(UPDATING_PROCESS_TOAST_TAG); toast_params toast_params{ UPDATING_PROCESS_TOAST_TAG, false }; - std::wstring new_version_ready{ GITHUB_NEW_VERSION_READY_TO_INSTALL }; + std::wstring new_version_ready{ strings.GITHUB_NEW_VERSION_READY_TO_INSTALL }; + new_version_ready += L'\n'; new_version_ready += current_version_to_next_version(info); show_toast_with_activations(std::move(new_version_ready), - TOAST_TITLE, + strings.TOAST_TITLE, {}, - { link_button{ GITHUB_NEW_VERSION_UPDATE_NOW, L"powertoys://update_now/" + info.installer_filename }, - link_button{ GITHUB_NEW_VERSION_UPDATE_AFTER_RESTART, L"powertoys://schedule_update/" + info.installer_filename }, - snooze_button{ GITHUB_NEW_VERSION_SNOOZE_TITLE, { { GITHUB_NEW_VERSION_UPDATE_SNOOZE_1D, 24 * 60 }, { GITHUB_NEW_VERSION_UPDATE_SNOOZE_5D, 120 * 60 } } } }, + { link_button{ strings.GITHUB_NEW_VERSION_UPDATE_NOW, + L"powertoys://update_now/" + info.installer_filename }, + link_button{ strings.GITHUB_NEW_VERSION_UPDATE_AFTER_RESTART, + L"powertoys://schedule_update/" + info.installer_filename }, + snooze_button{ + strings.GITHUB_NEW_VERSION_SNOOZE_TITLE, + { { strings.GITHUB_NEW_VERSION_UPDATE_SNOOZE_1D, 24 * 60 }, + { strings.GITHUB_NEW_VERSION_UPDATE_SNOOZE_5D, 120 * 60 } }, + strings.SNOOZE_BUTTON + } }, std::move(toast_params)); } - void show_uninstallation_error() + void show_uninstallation_error(const notifications::strings& strings) { remove_toasts(UPDATING_PROCESS_TOAST_TAG); - show_toast(localized_strings::UNINSTALLATION_UNKNOWN_ERROR, TOAST_TITLE); + show_toast(strings.UNINSTALLATION_UNKNOWN_ERROR, strings.TOAST_TITLE); } - void update_download_progress(const updating::new_version_download_info& info, float progress) + void update_download_progress(const updating::new_version_download_info& info, float progress, const notifications::strings& strings) { progress_bar_params progress_bar_params; std::wstring progress_title{ info.version_string }; progress_title += L' '; - progress_title += progress < 1 ? localized_strings::DOWNLOAD_IN_PROGRESS : localized_strings::DOWNLOAD_COMPLETE; + progress_title += progress < 1 ? strings.DOWNLOAD_IN_PROGRESS : strings.DOWNLOAD_COMPLETE; progress_bar_params.progress_title = progress_title; progress_bar_params.progress = progress; update_toast_progress_bar(UPDATING_PROCESS_TOAST_TAG, progress_bar_params); diff --git a/src/common/updating/notifications.h b/src/common/updating/notifications.h index 30f33f0470..0bd791620f 100644 --- a/src/common/updating/notifications.h +++ b/src/common/updating/notifications.h @@ -6,14 +6,66 @@ namespace updating 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_error(); + struct strings + { + std::wstring GITHUB_NEW_VERSION_AVAILABLE; + std::wstring GITHUB_NEW_VERSION_DOWNLOAD_STARTED; + std::wstring GITHUB_NEW_VERSION_READY_TO_INSTALL; + std::wstring GITHUB_NEW_VERSION_DOWNLOAD_INSTALL_ERROR; + std::wstring GITHUB_NEW_VERSION_UPDATE_NOW; + std::wstring GITHUB_NEW_VERSION_UPDATE_AFTER_RESTART; + std::wstring UNINSTALLATION_UNKNOWN_ERROR; + std::wstring GITHUB_NEW_VERSION_AVAILABLE_OFFER_VISIT; + std::wstring GITHUB_NEW_VERSION_UNAVAILABLE; + std::wstring GITHUB_NEW_VERSION_VISIT; + std::wstring GITHUB_NEW_VERSION_MORE_INFO; + std::wstring GITHUB_NEW_VERSION_ABORT; + std::wstring GITHUB_NEW_VERSION_SNOOZE_TITLE; + std::wstring SNOOZE_BUTTON; + std::wstring GITHUB_NEW_VERSION_UPDATE_SNOOZE_1D; + std::wstring GITHUB_NEW_VERSION_UPDATE_SNOOZE_5D; + std::wstring DOWNLOAD_IN_PROGRESS; + std::wstring DOWNLOAD_COMPLETE; + std::wstring TOAST_TITLE; + std::wstring OFFER_UNINSTALL_MSI; + std::wstring OFFER_UNINSTALL_MSI_TITLE; + template + static strings create() + { + return strings{ + .GITHUB_NEW_VERSION_AVAILABLE = GET_RESOURCE_STRING(IDS_GITHUB_NEW_VERSION_AVAILABLE), + .GITHUB_NEW_VERSION_DOWNLOAD_STARTED = GET_RESOURCE_STRING(IDS_GITHUB_NEW_VERSION_DOWNLOAD_STARTED), + .GITHUB_NEW_VERSION_READY_TO_INSTALL = GET_RESOURCE_STRING(IDS_GITHUB_NEW_VERSION_READY_TO_INSTALL), + .GITHUB_NEW_VERSION_DOWNLOAD_INSTALL_ERROR = GET_RESOURCE_STRING(IDS_GITHUB_NEW_VERSION_DOWNLOAD_INSTALL_ERROR), + .GITHUB_NEW_VERSION_UPDATE_NOW = GET_RESOURCE_STRING(IDS_GITHUB_NEW_VERSION_UPDATE_NOW), + .GITHUB_NEW_VERSION_UPDATE_AFTER_RESTART = GET_RESOURCE_STRING(IDS_GITHUB_NEW_VERSION_UPDATE_AFTER_RESTART), + .UNINSTALLATION_UNKNOWN_ERROR = GET_RESOURCE_STRING(IDS_UNINSTALLATION_UNKNOWN_ERROR), + .GITHUB_NEW_VERSION_AVAILABLE_OFFER_VISIT = GET_RESOURCE_STRING(IDS_GITHUB_NEW_VERSION_AVAILABLE_OFFER_VISIT), + .GITHUB_NEW_VERSION_UNAVAILABLE = GET_RESOURCE_STRING(IDS_GITHUB_NEW_VERSION_UNAVAILABLE), + .GITHUB_NEW_VERSION_VISIT = GET_RESOURCE_STRING(IDS_GITHUB_NEW_VERSION_VISIT), + .GITHUB_NEW_VERSION_MORE_INFO = GET_RESOURCE_STRING(IDS_GITHUB_NEW_VERSION_MORE_INFO), + .GITHUB_NEW_VERSION_ABORT = GET_RESOURCE_STRING(IDS_GITHUB_NEW_VERSION_ABORT), + .GITHUB_NEW_VERSION_SNOOZE_TITLE = GET_RESOURCE_STRING(IDS_GITHUB_NEW_VERSION_SNOOZE_TITLE), + .SNOOZE_BUTTON = GET_RESOURCE_STRING(IDS_SNOOZE_BUTTON), + .GITHUB_NEW_VERSION_UPDATE_SNOOZE_1D = GET_RESOURCE_STRING(IDS_GITHUB_NEW_VERSION_UPDATE_SNOOZE_1D), + .GITHUB_NEW_VERSION_UPDATE_SNOOZE_5D = GET_RESOURCE_STRING(IDS_GITHUB_NEW_VERSION_UPDATE_SNOOZE_5D), + .DOWNLOAD_IN_PROGRESS = GET_RESOURCE_STRING(IDS_DOWNLOAD_IN_PROGRESS), + .DOWNLOAD_COMPLETE = GET_RESOURCE_STRING(IDS_DOWNLOAD_COMPLETE), + .TOAST_TITLE = GET_RESOURCE_STRING(IDS_TOAST_TITLE), + .OFFER_UNINSTALL_MSI = GET_RESOURCE_STRING(IDS_OFFER_UNINSTALL_MSI), + .OFFER_UNINSTALL_MSI_TITLE = GET_RESOURCE_STRING(IDS_OFFER_UNINSTALL_MSI_TITLE) + }; + } + }; - void update_download_progress(const updating::new_version_download_info& info, float progress); + void show_unavailable(const notifications::strings& strings); + void show_available(const updating::new_version_download_info& info, const strings&); + void show_download_start(const updating::new_version_download_info& info, const strings&); + void show_visit_github(const updating::new_version_download_info& info, const strings&); + void show_install_error(const updating::new_version_download_info& info, const strings&); + void show_version_ready(const updating::new_version_download_info& info, const strings&); + void show_uninstallation_error(const notifications::strings& strings); + + void update_download_progress(const updating::new_version_download_info& info, float progress, const notifications::strings& strings); } } \ No newline at end of file diff --git a/src/common/updating/updating.cpp b/src/common/updating/updating.cpp index c2f0e6e536..0160d4b0fc 100644 --- a/src/common/updating/updating.cpp +++ b/src/common/updating/updating.cpp @@ -19,7 +19,7 @@ #include "VersionHelper.h" #include -namespace +namespace // Strings in this namespace should not be localized { const wchar_t POWER_TOYS_UPGRADE_CODE[] = L"{42B84BF7-5FBF-473B-9C8B-049DC16F7708}"; const wchar_t POWERTOYS_EXE_COMPONENT[] = L"{A2C66D91-3485-4D00-B04D-91844E6B345B}"; @@ -32,12 +32,6 @@ namespace const wchar_t TOAST_TITLE[] = L"PowerToys"; } -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?"; -} - namespace updating { std::wstring get_msi_package_path() @@ -73,13 +67,18 @@ namespace updating return package_path; } - bool offer_msi_uninstallation() + bool offer_msi_uninstallation(const notifications::strings& strings) { - 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); + const auto selection = SHMessageBoxCheckW(nullptr, + strings.OFFER_UNINSTALL_MSI.c_str(), + strings.OFFER_UNINSTALL_MSI_TITLE.c_str(), + MB_ICONQUESTION | MB_YESNO, + IDNO, + DONT_SHOW_AGAIN_RECORD_REGISTRY_PATH); return selection == IDYES; } - bool uninstall_msi_version(const std::wstring& package_path) + bool uninstall_msi_version(const std::wstring& package_path, const notifications::strings& strings) { const auto uninstall_result = MsiInstallProductW(package_path.c_str(), L"REMOVE=ALL"); if (ERROR_SUCCESS == uninstall_result) @@ -94,7 +93,7 @@ namespace updating } catch (...) { - updating::notifications::show_uninstallation_error(); + updating::notifications::show_uninstallation_error(strings); } } return false; @@ -202,7 +201,7 @@ namespace updating return installer_download_dst; } - std::future try_autoupdate(const bool download_updates_automatically) + std::future try_autoupdate(const bool download_updates_automatically, const notifications::strings& strings) { const auto new_version = co_await get_new_github_version_info_async(); if (!new_version) @@ -230,32 +229,32 @@ namespace updating } if (!download_success) { - updating::notifications::show_install_error(new_version.value()); + updating::notifications::show_install_error(new_version.value(), strings); co_return; } - updating::notifications::show_version_ready(new_version.value()); + updating::notifications::show_version_ready(new_version.value(), strings); } else { - updating::notifications::show_visit_github(new_version.value()); + updating::notifications::show_visit_github(new_version.value(), strings); } } - std::future check_new_version_available() + std::future check_new_version_available(const notifications::strings& strings) { const auto new_version = co_await get_new_github_version_info_async(); if (!new_version) { - updating::notifications::show_unavailable(); + updating::notifications::show_unavailable(strings); co_return VersionHelper{ VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION }.toWstring(); } - updating::notifications::show_available(new_version.value()); + updating::notifications::show_available(new_version.value(), strings); co_return new_version->version_string; } - std::future download_update() + std::future download_update(const notifications::strings& strings) { const auto new_version = co_await get_new_github_version_info_async(); if (!new_version) @@ -264,12 +263,12 @@ namespace updating } auto installer_download_dst = create_download_path() / new_version->installer_filename; - updating::notifications::show_download_start(new_version.value()); + updating::notifications::show_download_start(new_version.value(), strings); try { auto progressUpdateHandle = [&](float progress) { - updating::notifications::update_download_progress(new_version.value(), progress); + updating::notifications::update_download_progress(new_version.value(), progress, strings); }; http::HttpClient client; @@ -277,7 +276,7 @@ namespace updating } catch (...) { - updating::notifications::show_install_error(new_version.value()); + updating::notifications::show_install_error(new_version.value(), strings); co_return L""; } diff --git a/src/common/updating/updating.h b/src/common/updating/updating.h index 597a866b16..ea993f6d60 100644 --- a/src/common/updating/updating.h +++ b/src/common/updating/updating.h @@ -6,13 +6,14 @@ #include #include +#include "notifications.h" #include "../VersionHelper.h" namespace updating { std::wstring get_msi_package_path(); - bool uninstall_msi_version(const std::wstring& package_path); - bool offer_msi_uninstallation(); + bool uninstall_msi_version(const std::wstring& package_path, const notifications::strings&); + bool offer_msi_uninstallation(const notifications::strings&); std::optional get_msi_package_installed_path(); std::optional get_installed_powertoys_version(); @@ -27,11 +28,11 @@ namespace updating }; std::future> get_new_github_version_info_async(); - std::future try_autoupdate(const bool download_updates_automatically); + std::future try_autoupdate(const bool download_updates_automatically, const notifications::strings&); std::filesystem::path get_pending_updates_path(); - std::future check_new_version_available(); - std::future download_update(); + std::future check_new_version_available(const notifications::strings&); + std::future download_update(const notifications::strings&); // non-localized constexpr inline std::wstring_view INSTALLER_FILENAME_PATTERN = L"powertoyssetup"; diff --git a/src/core/Microsoft.PowerToys.Settings.UI.Library/ISettingsPath.cs b/src/core/Microsoft.PowerToys.Settings.UI.Library/ISettingsPath.cs new file mode 100644 index 0000000000..072058e4bc --- /dev/null +++ b/src/core/Microsoft.PowerToys.Settings.UI.Library/ISettingsPath.cs @@ -0,0 +1,17 @@ +// Copyright (c) Microsoft Corporation +// The Microsoft Corporation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.PowerToys.Settings.UI.Library +{ + public interface ISettingsPath + { + bool SettingsFolderExists(string powertoy); + + void CreateSettingsFolder(string powertoy); + + void DeleteSettings(string powertoy = ""); + + string GetSettingsPath(string powertoy, string fileName); + } +} diff --git a/src/core/Microsoft.PowerToys.Settings.UI.Library/Microsoft.PowerToys.Settings.UI.Library.csproj b/src/core/Microsoft.PowerToys.Settings.UI.Library/Microsoft.PowerToys.Settings.UI.Library.csproj index 4c94051072..dc4cf10d0b 100644 --- a/src/core/Microsoft.PowerToys.Settings.UI.Library/Microsoft.PowerToys.Settings.UI.Library.csproj +++ b/src/core/Microsoft.PowerToys.Settings.UI.Library/Microsoft.PowerToys.Settings.UI.Library.csproj @@ -41,6 +41,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive + 3.3.0 diff --git a/src/core/Microsoft.PowerToys.Settings.UI.Library/SettingPath.cs b/src/core/Microsoft.PowerToys.Settings.UI.Library/SettingPath.cs new file mode 100644 index 0000000000..65a1ea1244 --- /dev/null +++ b/src/core/Microsoft.PowerToys.Settings.UI.Library/SettingPath.cs @@ -0,0 +1,62 @@ +// Copyright (c) Microsoft Corporation +// The Microsoft Corporation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.IO.Abstractions; + +namespace Microsoft.PowerToys.Settings.UI.Library +{ + public class SettingPath : ISettingsPath + { + private const string DefaultFileName = "settings.json"; + + private readonly IDirectory _directory; + + private readonly IPath _path; + + public SettingPath(IDirectory directory, IPath path) + { + _directory = directory ?? throw new ArgumentNullException(nameof(directory)); + _path = path ?? throw new ArgumentNullException(nameof(path)); + } + + public bool SettingsFolderExists(string powertoy) + { + return _directory.Exists(System.IO.Path.Combine(LocalApplicationDataFolder(), $"Microsoft\\PowerToys\\{powertoy}")); + } + + public void CreateSettingsFolder(string powertoy) + { + _directory.CreateDirectory(System.IO.Path.Combine(LocalApplicationDataFolder(), $"Microsoft\\PowerToys\\{powertoy}")); + } + + public void DeleteSettings(string powertoy = "") + { + _directory.Delete(System.IO.Path.Combine(LocalApplicationDataFolder(), $"Microsoft\\PowerToys\\{powertoy}")); + } + + private static string LocalApplicationDataFolder() + { + return Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); + } + + /// + /// Get path to the json settings file. + /// + /// string path. + public string GetSettingsPath(string powertoy, string fileName = DefaultFileName) + { + if (string.IsNullOrWhiteSpace(powertoy)) + { + return _path.Combine( + LocalApplicationDataFolder(), + $"Microsoft\\PowerToys\\{fileName}"); + } + + return _path.Combine( + LocalApplicationDataFolder(), + $"Microsoft\\PowerToys\\{powertoy}\\{fileName}"); + } + } +} diff --git a/src/core/Microsoft.PowerToys.Settings.UI.Library/SettingsUtils.cs b/src/core/Microsoft.PowerToys.Settings.UI.Library/SettingsUtils.cs index 13a9b9ba69..e7fc1dec69 100644 --- a/src/core/Microsoft.PowerToys.Settings.UI.Library/SettingsUtils.cs +++ b/src/core/Microsoft.PowerToys.Settings.UI.Library/SettingsUtils.cs @@ -5,6 +5,7 @@ using System; using System.Diagnostics.CodeAnalysis; using System.IO; +using System.IO.Abstractions; using System.Text.Json; using Microsoft.PowerToys.Settings.UI.Library.Interfaces; using Microsoft.PowerToys.Settings.UI.Library.Utilities; @@ -15,49 +16,34 @@ namespace Microsoft.PowerToys.Settings.UI.Library { private const string DefaultFileName = "settings.json"; private const string DefaultModuleName = ""; - private IIOProvider _ioProvider; + private readonly IFile _file; + private readonly ISettingsPath _settingsPath; - public SettingsUtils(IIOProvider ioProvider) + public SettingsUtils() + : this(new FileSystem()) { - _ioProvider = ioProvider ?? throw new ArgumentNullException(nameof(ioProvider)); } - private bool SettingsFolderExists(string powertoy) + public SettingsUtils(IFileSystem fileSystem) + : this(fileSystem?.File, new SettingPath(fileSystem?.Directory, fileSystem?.Path)) { - return _ioProvider.DirectoryExists(System.IO.Path.Combine(LocalApplicationDataFolder(), $"Microsoft\\PowerToys\\{powertoy}")); } - private void CreateSettingsFolder(string powertoy) + public SettingsUtils(IFile file, ISettingsPath settingPath) { - _ioProvider.CreateDirectory(System.IO.Path.Combine(LocalApplicationDataFolder(), $"Microsoft\\PowerToys\\{powertoy}")); - } - - public void DeleteSettings(string powertoy = "") - { - _ioProvider.DeleteDirectory(System.IO.Path.Combine(LocalApplicationDataFolder(), $"Microsoft\\PowerToys\\{powertoy}")); - } - - /// - /// Get path to the json settings file. - /// - /// string path. - public static string GetSettingsPath(string powertoy, string fileName = DefaultFileName) - { - if (string.IsNullOrWhiteSpace(powertoy)) - { - return System.IO.Path.Combine( - LocalApplicationDataFolder(), - $"Microsoft\\PowerToys\\{fileName}"); - } - - return System.IO.Path.Combine( - LocalApplicationDataFolder(), - $"Microsoft\\PowerToys\\{powertoy}\\{fileName}"); + _file = file ?? throw new ArgumentNullException(nameof(file)); + _settingsPath = settingPath; } public bool SettingsExists(string powertoy = DefaultModuleName, string fileName = DefaultFileName) { - return _ioProvider.FileExists(GetSettingsPath(powertoy, fileName)); + var settingsPath = _settingsPath.GetSettingsPath(powertoy, fileName); + return _file.Exists(settingsPath); + } + + public void DeleteSettings(string powertoy = "") + { + _settingsPath.DeleteSettings(powertoy); } /// @@ -106,7 +92,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library // Look at issue https://github.com/microsoft/PowerToys/issues/6413 you'll see the file has a large sum of \0 to fill up a 4096 byte buffer for writing to disk // This, while not totally ideal, does work around the problem by trimming the end. // The file itself did write the content correctly but something is off with the actual end of the file, hence the 0x00 bug - var jsonSettingsString = _ioProvider.ReadAllText(GetSettingsPath(powertoyFolderName, fileName)).Trim('\0'); + var jsonSettingsString = _file.ReadAllText(_settingsPath.GetSettingsPath(powertoyFolderName, fileName)).Trim('\0'); return JsonSerializer.Deserialize(jsonSettingsString); } @@ -118,12 +104,12 @@ namespace Microsoft.PowerToys.Settings.UI.Library { if (jsonSettings != null) { - if (!SettingsFolderExists(powertoy)) + if (!_settingsPath.SettingsFolderExists(powertoy)) { - CreateSettingsFolder(powertoy); + _settingsPath.CreateSettingsFolder(powertoy); } - _ioProvider.WriteAllText(GetSettingsPath(powertoy, fileName), jsonSettings); + _file.WriteAllText(_settingsPath.GetSettingsPath(powertoy, fileName), jsonSettings); } } catch (Exception e) @@ -137,10 +123,5 @@ namespace Microsoft.PowerToys.Settings.UI.Library #endif } } - - private static string LocalApplicationDataFolder() - { - return Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); - } } } diff --git a/src/core/Microsoft.PowerToys.Settings.UI.Library/Utilities/Helper.cs b/src/core/Microsoft.PowerToys.Settings.UI.Library/Utilities/Helper.cs index 8cce1f2a68..22b2964592 100644 --- a/src/core/Microsoft.PowerToys.Settings.UI.Library/Utilities/Helper.cs +++ b/src/core/Microsoft.PowerToys.Settings.UI.Library/Utilities/Helper.cs @@ -5,6 +5,7 @@ using System; using System.Diagnostics; using System.IO; +using System.IO.Abstractions; using System.Linq; using System.Runtime.InteropServices; using Microsoft.PowerToys.Settings.UI.Library.CustomAction; @@ -13,6 +14,8 @@ namespace Microsoft.PowerToys.Settings.UI.Library.Utilities { public static class Helper { + public static readonly IFileSystem FileSystem = new FileSystem(); + public static bool AllowRunnerToForeground() { var result = false; @@ -47,22 +50,20 @@ namespace Microsoft.PowerToys.Settings.UI.Library.Utilities return sendCustomAction.ToJsonString(); } - public static FileSystemWatcher GetFileWatcher(string moduleName, string fileName, Action onChangedCallback) + public static IFileSystemWatcher GetFileWatcher(string moduleName, string fileName, Action onChangedCallback) { - var path = Path.Combine(LocalApplicationDataFolder(), $"Microsoft\\PowerToys\\{moduleName}"); + var path = FileSystem.Path.Combine(LocalApplicationDataFolder(), $"Microsoft\\PowerToys\\{moduleName}"); - if (!Directory.Exists(path)) + if (!FileSystem.Directory.Exists(path)) { - Directory.CreateDirectory(path); + FileSystem.Directory.CreateDirectory(path); } - var watcher = new FileSystemWatcher - { - Path = path, - Filter = fileName, - NotifyFilter = NotifyFilters.LastWrite, - EnableRaisingEvents = true, - }; + var watcher = FileSystem.FileSystemWatcher.CreateNew(); + watcher.Path = path; + watcher.Filter = fileName; + watcher.NotifyFilter = NotifyFilters.LastWrite; + watcher.EnableRaisingEvents = true; watcher.Changed += (o, e) => onChangedCallback(); diff --git a/src/core/Microsoft.PowerToys.Settings.UI.Library/Utilities/Logger.cs b/src/core/Microsoft.PowerToys.Settings.UI.Library/Utilities/Logger.cs index 7d98018af7..fbac2c88fb 100644 --- a/src/core/Microsoft.PowerToys.Settings.UI.Library/Utilities/Logger.cs +++ b/src/core/Microsoft.PowerToys.Settings.UI.Library/Utilities/Logger.cs @@ -5,12 +5,16 @@ using System; using System.Diagnostics; using System.Globalization; -using System.IO; +using System.IO.Abstractions; namespace Microsoft.PowerToys.Settings.UI.Library.Utilities { public static class Logger { + private static readonly IFileSystem FileSystem = new FileSystem(); + private static readonly IPath Path = FileSystem.Path; + private static readonly IDirectory Directory = FileSystem.Directory; + private static readonly string ApplicationLogPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Microsoft\\PowerToys\\Settings Logs"); static Logger() @@ -20,6 +24,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library.Utilities Directory.CreateDirectory(ApplicationLogPath); } + // Using InvariantCulture since this is used for a log file name var logFilePath = Path.Combine(ApplicationLogPath, "Log_" + DateTime.Now.ToString(@"yyyy-MM-dd", CultureInfo.InvariantCulture) + ".txt"); Trace.Listeners.Add(new TextWriterTraceListener(logFilePath)); diff --git a/src/core/Microsoft.PowerToys.Settings.UI.Library/Utilities/SystemIOProvider.cs b/src/core/Microsoft.PowerToys.Settings.UI.Library/Utilities/SystemIOProvider.cs index 8519f90319..f2895ffd4e 100644 --- a/src/core/Microsoft.PowerToys.Settings.UI.Library/Utilities/SystemIOProvider.cs +++ b/src/core/Microsoft.PowerToys.Settings.UI.Library/Utilities/SystemIOProvider.cs @@ -2,41 +2,61 @@ // The Microsoft Corporation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System.IO; +using System; +using System.IO.Abstractions; namespace Microsoft.PowerToys.Settings.UI.Library.Utilities { public class SystemIOProvider : IIOProvider { + private readonly IDirectory _directory; + private readonly IFile _file; + + public SystemIOProvider() + : this(new FileSystem()) + { + } + + public SystemIOProvider(IFileSystem fileSystem) + : this(fileSystem?.Directory, fileSystem?.File) + { + } + + private SystemIOProvider(IDirectory directory, IFile file) + { + _directory = directory ?? throw new ArgumentNullException(nameof(directory)); + _file = file ?? throw new ArgumentNullException(nameof(file)); + } + public bool CreateDirectory(string path) { - var directoryInfo = Directory.CreateDirectory(path); + var directoryInfo = _directory.CreateDirectory(path); return directoryInfo != null; } public void DeleteDirectory(string path) { - Directory.Delete(path, recursive: true); + _directory.Delete(path, recursive: true); } public bool DirectoryExists(string path) { - return Directory.Exists(path); + return _directory.Exists(path); } public bool FileExists(string path) { - return File.Exists(path); + return _file.Exists(path); } public string ReadAllText(string path) { - return File.ReadAllText(path); + return _file.ReadAllText(path); } public void WriteAllText(string path, string content) { - File.WriteAllText(path, content); + _file.WriteAllText(path, content); } } } diff --git a/src/core/Microsoft.PowerToys.Settings.UI.UnitTests/BackwardsCompatibility/BackCompatTestProperties.cs b/src/core/Microsoft.PowerToys.Settings.UI.UnitTests/BackwardsCompatibility/BackCompatTestProperties.cs index 28ed4f04bc..36ec7b6ffa 100644 --- a/src/core/Microsoft.PowerToys.Settings.UI.UnitTests/BackwardsCompatibility/BackCompatTestProperties.cs +++ b/src/core/Microsoft.PowerToys.Settings.UI.UnitTests/BackwardsCompatibility/BackCompatTestProperties.cs @@ -1,13 +1,11 @@ using Microsoft.PowerToys.Settings.UI.Library; using Microsoft.PowerToys.Settings.UI.Library.Interfaces; -using Microsoft.PowerToys.Settings.UI.Library.Utilities; using Microsoft.PowerToys.Settings.UI.UnitTests.Mocks; using Moq; using System; -using System.Collections.Generic; using System.Globalization; +using System.IO.Abstractions; using System.Linq.Expressions; -using System.Text; namespace Microsoft.PowerToys.Settings.UI.UnitTests.BackwardsCompatibility { @@ -15,6 +13,9 @@ namespace Microsoft.PowerToys.Settings.UI.UnitTests.BackwardsCompatibility { public const string RootPathStubFiles = "..\\..\\..\\..\\src\\core\\Microsoft.PowerToys.Settings.UI.UnitTests\\BackwardsCompatibility\\TestFiles\\{0}\\Microsoft\\PowerToys\\{1}\\{2}"; + // Using Ordinal since this is used internally for a path + private static readonly Expression> SettingsFilterExpression = s => s == null || s.Contains("Microsoft\\PowerToys\\settings.json", StringComparison.Ordinal); + internal class MockSettingsRepository : ISettingsRepository where T : ISettingsConfig, new() { T _settingsConfig; @@ -43,44 +44,56 @@ namespace Microsoft.PowerToys.Settings.UI.UnitTests.BackwardsCompatibility } - public static MockGetModuleIOProvider(string version, string module, string fileName) + public static MockGetModuleIOProvider(string version, string module, string fileName) { - var stubSettingsPath = string.Format(CultureInfo.InvariantCulture, BackCompatTestProperties.RootPathStubFiles, version, module, fileName); - Expression> filterExpression = (string s) => s.Contains(module, StringComparison.Ordinal); - var mockIOProvider = IIOProviderMocks.GetMockIOReadWithStubFile(stubSettingsPath, filterExpression); - return mockIOProvider; + var stubSettingsPath = StubSettingsPath(version, module, fileName); + Expression> filterExpression = ModuleFilterExpression(module); + return IIOProviderMocks.GetMockIOReadWithStubFile(stubSettingsPath, filterExpression); } - public static void VerifyModuleIOProviderWasRead(Mock provider, string module, int expectedCallCount) + public static string StubGeneralSettingsPath(string version) + { + return StubSettingsPath(version, string.Empty, "settings.json"); + } + + public static string StubSettingsPath(string version, string module, string fileName) + { + return string.Format(CultureInfo.InvariantCulture, BackCompatTestProperties.RootPathStubFiles, version, module, fileName); + } + + public static void VerifyModuleIOProviderWasRead(Mock provider, string module, int expectedCallCount) { if(provider == null) { throw new ArgumentNullException(nameof(provider)); } - Expression> filterExpression = (string s) => s.Contains(module, StringComparison.Ordinal); + Expression> filterExpression = ModuleFilterExpression(module); IIOProviderMocks.VerifyIOReadWithStubFile(provider, filterExpression, expectedCallCount); } - public static Mock GetGeneralSettingsIOProvider(string version) + private static Expression> ModuleFilterExpression(string module) { - var stubGeneralSettingsPath = string.Format(CultureInfo.InvariantCulture, BackCompatTestProperties.RootPathStubFiles, version, string.Empty, "settings.json"); - Expression> filterExpression = (string s) => s.Contains("Microsoft\\PowerToys\\settings.json", StringComparison.Ordinal); - var mockGeneralIOProvider = IIOProviderMocks.GetMockIOReadWithStubFile(stubGeneralSettingsPath, filterExpression); - return mockGeneralIOProvider; + // Using Ordinal since this is used internally for a path + return s => s == null || s.Contains(module, StringComparison.Ordinal); } - public static void VerifyGeneralSettingsIOProviderWasRead(Mock provider, int expectedCallCount) + public static Mock GetGeneralSettingsIOProvider(string version) + { + var stubGeneralSettingsPath = StubGeneralSettingsPath(version); + return IIOProviderMocks.GetMockIOReadWithStubFile(stubGeneralSettingsPath, SettingsFilterExpression); + } + + public static void VerifyGeneralSettingsIOProviderWasRead(Mock provider, int expectedCallCount) { if (provider == null) { throw new ArgumentNullException(nameof(provider)); } - Expression> filterExpression = (string s) => s.Contains("Microsoft\\PowerToys\\settings.json", StringComparison.Ordinal); - IIOProviderMocks.VerifyIOReadWithStubFile(provider, filterExpression, expectedCallCount); + IIOProviderMocks.VerifyIOReadWithStubFile(provider, SettingsFilterExpression, expectedCallCount); } } diff --git a/src/core/Microsoft.PowerToys.Settings.UI.UnitTests/BackwardsCompatibility/TestFiles/CorruptJson/Microsoft/PowerToys/settings.json b/src/core/Microsoft.PowerToys.Settings.UI.UnitTests/BackwardsCompatibility/TestFiles/CorruptJson/Microsoft/PowerToys/settings.json new file mode 100644 index 0000000000..7e9dae7531 Binary files /dev/null and b/src/core/Microsoft.PowerToys.Settings.UI.UnitTests/BackwardsCompatibility/TestFiles/CorruptJson/Microsoft/PowerToys/settings.json differ diff --git a/src/core/Microsoft.PowerToys.Settings.UI.UnitTests/Microsoft.PowerToys.Settings.UI.UnitTests.csproj b/src/core/Microsoft.PowerToys.Settings.UI.UnitTests/Microsoft.PowerToys.Settings.UI.UnitTests.csproj index 77c03e0bce..92d996e1aa 100644 --- a/src/core/Microsoft.PowerToys.Settings.UI.UnitTests/Microsoft.PowerToys.Settings.UI.UnitTests.csproj +++ b/src/core/Microsoft.PowerToys.Settings.UI.UnitTests/Microsoft.PowerToys.Settings.UI.UnitTests.csproj @@ -29,6 +29,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all + diff --git a/src/core/Microsoft.PowerToys.Settings.UI.UnitTests/Mocks/IIOProviderMocks.cs b/src/core/Microsoft.PowerToys.Settings.UI.UnitTests/Mocks/IIOProviderMocks.cs index 9a0b7433ec..226e243b08 100644 --- a/src/core/Microsoft.PowerToys.Settings.UI.UnitTests/Mocks/IIOProviderMocks.cs +++ b/src/core/Microsoft.PowerToys.Settings.UI.UnitTests/Mocks/IIOProviderMocks.cs @@ -1,10 +1,9 @@ using Microsoft.PowerToys.Settings.UI.Library.Utilities; using Moq; using System; -using System.Collections.Generic; -using System.IO; +using System.IO.Abstractions; +using System.IO.Abstractions.TestingHelpers; using System.Linq.Expressions; -using System.Text; namespace Microsoft.PowerToys.Settings.UI.UnitTests.Mocks { @@ -26,11 +25,13 @@ namespace Microsoft.PowerToys.Settings.UI.UnitTests.Mocks savePath = path; saveContent = content; }); + // Using Ordinal since this is used internally for a path mockIOProvider.Setup(x => x.ReadAllText(It.Is(x => x.Equals(savePath, StringComparison.Ordinal)))) .Returns(() => saveContent); - + // Using Ordinal since this is used internally for a path mockIOProvider.Setup(x => x.FileExists(It.Is(x => x.Equals(savePath, StringComparison.Ordinal)))) .Returns(true); + // Using Ordinal since this is used internally for a path mockIOProvider.Setup(x => x.FileExists(It.Is(x => !x.Equals(savePath, StringComparison.Ordinal)))) .Returns(false); @@ -39,6 +40,8 @@ namespace Microsoft.PowerToys.Settings.UI.UnitTests.Mocks + private static readonly IFileSystem FileSystem = new FileSystem(); + private static readonly IFile File = FileSystem.File; /// /// This method mocks an IO provider so that it will always return data at the savePath location. /// This mock is specific to a given module, and is verifiable that the stub file was read. @@ -46,25 +49,25 @@ namespace Microsoft.PowerToys.Settings.UI.UnitTests.Mocks /// The path to the stub settings file /// The substring in the path that identifies the module eg. Microsoft\\PowerToys\\ColorPicker /// - internal static Mock GetMockIOReadWithStubFile(string savePath, Expression> filterExpression) + internal static Mock GetMockIOReadWithStubFile(string savePath, Expression> filterExpression) { string saveContent = File.ReadAllText(savePath); - var mockIOProvider = new Mock(); + var fileMock = new Mock(); - mockIOProvider.Setup(x => x.ReadAllText(It.Is(filterExpression))) + fileMock.Setup(x => x.ReadAllText(It.Is(filterExpression))) .Returns(() => saveContent).Verifiable(); - mockIOProvider.Setup(x => x.FileExists(It.Is(filterExpression))) + fileMock.Setup(x => x.Exists(It.Is(filterExpression))) .Returns(true); - return mockIOProvider; + return fileMock; } - internal static void VerifyIOReadWithStubFile(Mock mockIOProvider, Expression> filterExpression, int expectedCallCount) + internal static void VerifyIOReadWithStubFile(Mock fileMock, Expression> filterExpression, int expectedCallCount) { - mockIOProvider.Verify(x => x.ReadAllText(It.Is(filterExpression)), Times.Exactly(expectedCallCount)); + fileMock.Verify(x => x.ReadAllText(It.Is(filterExpression)), Times.Exactly(expectedCallCount)); } } } diff --git a/src/core/Microsoft.PowerToys.Settings.UI.UnitTests/ModelsTests/BasePTModuleSettingsTest.cs b/src/core/Microsoft.PowerToys.Settings.UI.UnitTests/ModelsTests/BasePTModuleSettingsTest.cs index 99555c4649..67daf9a363 100644 --- a/src/core/Microsoft.PowerToys.Settings.UI.UnitTests/ModelsTests/BasePTModuleSettingsTest.cs +++ b/src/core/Microsoft.PowerToys.Settings.UI.UnitTests/ModelsTests/BasePTModuleSettingsTest.cs @@ -6,9 +6,9 @@ using System; using Microsoft.PowerToys.Settings.UI.Library; using Microsoft.PowerToys.Settings.UI.Library.Utilities; using Microsoft.PowerToys.Settings.UI.UnitTests.Mocks; +using System.IO.Abstractions.TestingHelpers; using Microsoft.PowerToys.Settings.UnitTest; using Microsoft.VisualStudio.TestTools.UnitTesting; -using Moq; using Newtonsoft.Json.Linq; using Newtonsoft.Json.Schema; @@ -25,11 +25,8 @@ namespace CommonLibTest public void ToJsonStringShouldReturnValidJSONOfModelWhenSuccessful() { //Mock Disk access - string saveContent = string.Empty; - string savePath = string.Empty; - var mockIOProvider = IIOProviderMocks.GetMockIOProviderForSaveLoadExists(); - - var settingsUtils = new SettingsUtils(mockIOProvider.Object); + var mockFileSystem = new MockFileSystem(); + var settingsUtils = new SettingsUtils(mockFileSystem); // Arrange string file_name = "test\\BasePTModuleSettingsTest"; diff --git a/src/core/Microsoft.PowerToys.Settings.UI.UnitTests/ModelsTests/SettingsRepositoryTest.cs b/src/core/Microsoft.PowerToys.Settings.UI.UnitTests/ModelsTests/SettingsRepositoryTest.cs index 99501ff2e6..ced10464d9 100644 --- a/src/core/Microsoft.PowerToys.Settings.UI.UnitTests/ModelsTests/SettingsRepositoryTest.cs +++ b/src/core/Microsoft.PowerToys.Settings.UI.UnitTests/ModelsTests/SettingsRepositoryTest.cs @@ -2,9 +2,7 @@ // The Microsoft Corporation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; using System.Collections.Generic; -using System.IO; using System.Threading.Tasks; using Microsoft.PowerToys.Settings.UI.Library; using Microsoft.VisualStudio.TestTools.UnitTesting; diff --git a/src/core/Microsoft.PowerToys.Settings.UI.UnitTests/ModelsTests/SettingsUtilsTests.cs b/src/core/Microsoft.PowerToys.Settings.UI.UnitTests/ModelsTests/SettingsUtilsTests.cs index 1289f7015d..9c60f9b8b3 100644 --- a/src/core/Microsoft.PowerToys.Settings.UI.UnitTests/ModelsTests/SettingsUtilsTests.cs +++ b/src/core/Microsoft.PowerToys.Settings.UI.UnitTests/ModelsTests/SettingsUtilsTests.cs @@ -3,11 +3,14 @@ // See the LICENSE file in the project root for more information. using System; -using System.IO; +using System.IO.Abstractions; +using System.IO.Abstractions.TestingHelpers; using System.Linq; using System.Text.Json; using Microsoft.PowerToys.Settings.UI.Library; +using Microsoft.PowerToys.Settings.UI.Library.Interfaces; using Microsoft.PowerToys.Settings.UI.Library.Utilities; +using Microsoft.PowerToys.Settings.UI.UnitTests.BackwardsCompatibility; using Microsoft.PowerToys.Settings.UI.UnitTests.Mocks; using Microsoft.PowerToys.Settings.UnitTest; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -19,14 +22,13 @@ namespace CommonLibTest public class SettingsUtilsTests { - [TestMethod] public void SaveSettingsSaveSettingsToFileWhenFilePathExists() { // Arrange - var mockIOProvider = IIOProviderMocks.GetMockIOProviderForSaveLoadExists(); - var settingsUtils = new SettingsUtils(mockIOProvider.Object); - + var mockFileSystem = new MockFileSystem(); + var settingsUtils = new SettingsUtils(mockFileSystem); + string file_name = "\\test"; string file_contents_correct_json_content = "{\"name\":\"powertoy module name\",\"version\":\"powertoy version\"}"; @@ -44,8 +46,8 @@ namespace CommonLibTest public void SaveSettingsShouldCreateFileWhenFilePathIsNotFound() { // Arrange - var mockIOProvider = IIOProviderMocks.GetMockIOProviderForSaveLoadExists(); - var settingsUtils = new SettingsUtils(mockIOProvider.Object); + var mockFileSystem = new MockFileSystem(); + var settingsUtils = new SettingsUtils(mockFileSystem); string file_name = "test\\Test Folder"; string file_contents_correct_json_content = "{\"name\":\"powertoy module name\",\"version\":\"powertoy version\"}"; @@ -62,8 +64,8 @@ namespace CommonLibTest public void SettingsFolderExistsShouldReturnFalseWhenFilePathIsNotFound() { // Arrange - var mockIOProvider = IIOProviderMocks.GetMockIOProviderForSaveLoadExists(); - var settingsUtils = new SettingsUtils(mockIOProvider.Object); + var mockFileSystem = new MockFileSystem(); + var settingsUtils = new SettingsUtils(mockFileSystem); string file_name_random = "test\\" + RandomString(); string file_name_exists = "test\\exists"; string file_contents_correct_json_content = "{\"name\":\"powertoy module name\",\"version\":\"powertoy version\"}"; @@ -79,6 +81,21 @@ namespace CommonLibTest Assert.IsTrue(pathFound); } + [TestMethod] + public void SettingsUtilsMustReturnDefaultItemWhenFileIsCorrupt() + { + // Arrange + var mockFileSystem = new MockFileSystem(); + var mockSettingsUtils = new SettingsUtils(mockFileSystem); + + // Act + TestClass settings = mockSettingsUtils.GetSettings(string.Empty); + + // Assert + Assert.AreEqual(settings.TestInt, 100); + Assert.AreEqual(settings.TestString, "test"); + } + public static string RandomString() { Random random = new Random(); @@ -88,5 +105,26 @@ namespace CommonLibTest return new string(Enumerable.Repeat(chars, length) .Select(s => s[random.Next(s.Length)]).ToArray()); } + + partial class TestClass : ISettingsConfig + { + public int TestInt { get; set; } = 100; + public string TestString { get; set; } = "test"; + + public string GetModuleName() + { + throw new NotImplementedException(); + } + + public string ToJsonString() + { + return JsonSerializer.Serialize(this); + } + + public bool UpgradeSettingsConfiguration() + { + throw new NotImplementedException(); + } + } } } diff --git a/src/core/Microsoft.PowerToys.Settings.UI.UnitTests/ViewModelTests/ColorPicker.cs b/src/core/Microsoft.PowerToys.Settings.UI.UnitTests/ViewModelTests/ColorPicker.cs index 1ddc93c17f..01efdd2370 100644 --- a/src/core/Microsoft.PowerToys.Settings.UI.UnitTests/ViewModelTests/ColorPicker.cs +++ b/src/core/Microsoft.PowerToys.Settings.UI.UnitTests/ViewModelTests/ColorPicker.cs @@ -2,14 +2,13 @@ // The Microsoft Corporation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System.Globalization; -using System.IO; using System.Text.Json; using Microsoft.PowerToys.Settings.UI.Library; using Microsoft.PowerToys.Settings.UI.Library.ViewModels; using Microsoft.PowerToys.Settings.UI.UnitTests.BackwardsCompatibility; using Microsoft.PowerToys.Settings.UI.UnitTests.Mocks; using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; namespace ViewModelTests { @@ -27,11 +26,14 @@ namespace ViewModelTests { //Arrange var mockIOProvider = BackCompatTestProperties.GetModuleIOProvider(version, ColorPickerSettings.ModuleName, fileName); - var mockSettingsUtils = new SettingsUtils(mockIOProvider.Object); + var settingPathMock = new Mock(); + + var mockSettingsUtils = new SettingsUtils(mockIOProvider.Object, settingPathMock.Object); ColorPickerSettings originalSettings = mockSettingsUtils.GetSettings(ColorPickerSettings.ModuleName); var mockGeneralIOProvider = BackCompatTestProperties.GetGeneralSettingsIOProvider(version); - var mockGeneralSettingsUtils = new SettingsUtils(mockGeneralIOProvider.Object); + + var mockGeneralSettingsUtils = new SettingsUtils(mockGeneralIOProvider.Object, settingPathMock.Object); GeneralSettings originalGeneralSettings = mockGeneralSettingsUtils.GetSettings(); var generalSettingsRepository = new BackCompatTestProperties.MockSettingsRepository(mockGeneralSettingsUtils); diff --git a/src/core/Microsoft.PowerToys.Settings.UI.UnitTests/ViewModelTests/FancyZones.cs b/src/core/Microsoft.PowerToys.Settings.UI.UnitTests/ViewModelTests/FancyZones.cs index ead763064c..d40f1d9e94 100644 --- a/src/core/Microsoft.PowerToys.Settings.UI.UnitTests/ViewModelTests/FancyZones.cs +++ b/src/core/Microsoft.PowerToys.Settings.UI.UnitTests/ViewModelTests/FancyZones.cs @@ -3,9 +3,6 @@ // See the LICENSE file in the project root for more information. using System; -using System.Drawing; -using System.Globalization; -using System.IO; using System.Text.Json; using CommonLibTest; using Microsoft.PowerToys.Settings.UI.Library; @@ -33,13 +30,16 @@ namespace ViewModelTests [DataRow("v0.22.0", "settings.json")] public void OriginalFilesModificationTest(string version, string fileName) { - var mockIOProvider = BackCompatTestProperties.GetModuleIOProvider(version, FancyZonesSettings.ModuleName, fileName); - var mockSettingsUtils = new SettingsUtils(mockIOProvider.Object); + var settingPathMock = new Mock(); + + var fileMock = BackCompatTestProperties.GetModuleIOProvider(version, FancyZonesSettings.ModuleName, fileName); + var mockSettingsUtils = new SettingsUtils(fileMock.Object, settingPathMock.Object); FancyZonesSettings originalSettings = mockSettingsUtils.GetSettings(FancyZonesSettings.ModuleName); var mockGeneralIOProvider = BackCompatTestProperties.GetGeneralSettingsIOProvider(version); - var mockGeneralSettingsUtils = new SettingsUtils(mockGeneralIOProvider.Object); + var mockGeneralSettingsUtils = new SettingsUtils(mockGeneralIOProvider.Object, settingPathMock.Object); GeneralSettings originalGeneralSettings = mockGeneralSettingsUtils.GetSettings(); + var generalSettingsRepository = new BackCompatTestProperties.MockSettingsRepository(mockGeneralSettingsUtils); var fancyZonesRepository = new BackCompatTestProperties.MockSettingsRepository(mockSettingsUtils); @@ -71,7 +71,7 @@ namespace ViewModelTests //Verify that the stub file was used var expectedCallCount = 2; //once via the view model, and once by the test (GetSettings) - BackCompatTestProperties.VerifyModuleIOProviderWasRead(mockIOProvider, FancyZonesSettings.ModuleName, expectedCallCount); + BackCompatTestProperties.VerifyModuleIOProviderWasRead(fileMock, FancyZonesSettings.ModuleName, expectedCallCount); BackCompatTestProperties.VerifyGeneralSettingsIOProviderWasRead(mockGeneralIOProvider, expectedCallCount); } diff --git a/src/core/Microsoft.PowerToys.Settings.UI.UnitTests/ViewModelTests/General.cs b/src/core/Microsoft.PowerToys.Settings.UI.UnitTests/ViewModelTests/General.cs index 167037fc38..98a5a19bd4 100644 --- a/src/core/Microsoft.PowerToys.Settings.UI.UnitTests/ViewModelTests/General.cs +++ b/src/core/Microsoft.PowerToys.Settings.UI.UnitTests/ViewModelTests/General.cs @@ -4,7 +4,6 @@ using System; using System.Globalization; -using System.IO; using System.Text.Json; using Microsoft.PowerToys.Settings.UI.Library; using Microsoft.PowerToys.Settings.UI.Library.ViewModels; @@ -12,7 +11,7 @@ using Microsoft.PowerToys.Settings.UI.UnitTests.BackwardsCompatibility; using Microsoft.PowerToys.Settings.UI.UnitTests.Mocks; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; -using NuGet.Frameworks; +using JsonSerializer = System.Text.Json.JsonSerializer; namespace ViewModelTests { @@ -40,16 +39,20 @@ namespace ViewModelTests [DataRow("v0.22.0")] public void OriginalFilesModificationTest(string version) { - var mockGeneralIOProvider = BackCompatTestProperties.GetGeneralSettingsIOProvider(version); - var mockGeneralSettingsUtils = new SettingsUtils(mockGeneralIOProvider.Object); + var settingPathMock = new Mock(); + var fileMock = BackCompatTestProperties.GetGeneralSettingsIOProvider(version); + + var mockGeneralSettingsUtils = new SettingsUtils(fileMock.Object, settingPathMock.Object); GeneralSettings originalGeneralSettings = mockGeneralSettingsUtils.GetSettings(); + var generalSettingsRepository = new BackCompatTestProperties.MockSettingsRepository(mockGeneralSettingsUtils); + // Initialise View Model with test Config files // Arrange - Func SendMockIPCConfigMSG = msg => { return 0; }; - Func SendRestartAdminIPCMessage = msg => { return 0; }; - Func SendCheckForUpdatesIPCMessage = msg => { return 0; }; + Func SendMockIPCConfigMSG = msg => 0; + Func SendRestartAdminIPCMessage = msg => 0; + Func SendCheckForUpdatesIPCMessage = msg => 0; var viewModel = new GeneralViewModel( settingsRepository: generalSettingsRepository, runAsAdminText: "GeneralSettings_RunningAsAdminText", @@ -71,7 +74,7 @@ namespace ViewModelTests //Verify that the stub file was used var expectedCallCount = 2; //once via the view model, and once by the test (GetSettings) - BackCompatTestProperties.VerifyGeneralSettingsIOProviderWasRead(mockGeneralIOProvider, expectedCallCount); + BackCompatTestProperties.VerifyGeneralSettingsIOProviderWasRead(fileMock, expectedCallCount); } [TestMethod] @@ -82,7 +85,7 @@ namespace ViewModelTests Func SendRestartAdminIPCMessage = msg => { return 0; }; Func SendCheckForUpdatesIPCMessage = msg => { return 0; }; GeneralViewModel viewModel = new GeneralViewModel( - SettingsRepository.GetInstance(mockGeneralSettingsUtils.Object), + settingsRepository: SettingsRepository.GetInstance(mockGeneralSettingsUtils.Object), "GeneralSettings_RunningAsAdminText", "GeneralSettings_RunningAsUserText", false, @@ -119,7 +122,7 @@ namespace ViewModelTests Func SendRestartAdminIPCMessage = msg => { return 0; }; Func SendCheckForUpdatesIPCMessage = msg => { return 0; }; GeneralViewModel viewModel = new GeneralViewModel( - SettingsRepository.GetInstance(mockGeneralSettingsUtils.Object), + settingsRepository: SettingsRepository.GetInstance(mockGeneralSettingsUtils.Object), "GeneralSettings_RunningAsAdminText", "GeneralSettings_RunningAsUserText", false, @@ -151,7 +154,7 @@ namespace ViewModelTests // Arrange GeneralViewModel viewModel = new GeneralViewModel( - SettingsRepository.GetInstance(mockGeneralSettingsUtils.Object), + settingsRepository: SettingsRepository.GetInstance(mockGeneralSettingsUtils.Object), "GeneralSettings_RunningAsAdminText", "GeneralSettings_RunningAsUserText", false, @@ -184,7 +187,7 @@ namespace ViewModelTests Func SendRestartAdminIPCMessage = msg => { return 0; }; Func SendCheckForUpdatesIPCMessage = msg => { return 0; }; viewModel = new GeneralViewModel( - SettingsRepository.GetInstance(mockGeneralSettingsUtils.Object), + settingsRepository: SettingsRepository.GetInstance(mockGeneralSettingsUtils.Object), "GeneralSettings_RunningAsAdminText", "GeneralSettings_RunningAsUserText", false, @@ -215,7 +218,7 @@ namespace ViewModelTests Func SendRestartAdminIPCMessage = msg => { return 0; }; Func SendCheckForUpdatesIPCMessage = msg => { return 0; }; GeneralViewModel viewModel = new GeneralViewModel( - SettingsRepository.GetInstance(mockGeneralSettingsUtils.Object), + settingsRepository: SettingsRepository.GetInstance(mockGeneralSettingsUtils.Object), "GeneralSettings_RunningAsAdminText", "GeneralSettings_RunningAsUserText", false, diff --git a/src/core/Microsoft.PowerToys.Settings.UI.UnitTests/ViewModelTests/ImageResizer.cs b/src/core/Microsoft.PowerToys.Settings.UI.UnitTests/ViewModelTests/ImageResizer.cs index 2ea3590483..452b54a8d9 100644 --- a/src/core/Microsoft.PowerToys.Settings.UI.UnitTests/ViewModelTests/ImageResizer.cs +++ b/src/core/Microsoft.PowerToys.Settings.UI.UnitTests/ViewModelTests/ImageResizer.cs @@ -3,8 +3,8 @@ // See the LICENSE file in the project root for more information. using System; -using System.Globalization; -using System.IO; +using System.IO.Abstractions; +using System.IO.Abstractions.TestingHelpers; using System.Linq; using System.Text.Json; using Microsoft.PowerToys.Settings.UI.Library; @@ -20,16 +20,15 @@ namespace ViewModelTests [TestClass] public class ImageResizer { + private Mock _mockGeneralSettingsUtils; - private Mock mockGeneralSettingsUtils; - - private Mock mockImgResizerSettingsUtils; + private Mock _mockImgResizerSettingsUtils; [TestInitialize] public void SetUpStubSettingUtils() { - mockGeneralSettingsUtils = ISettingsUtilsMocks.GetStubSettingsUtils(); - mockImgResizerSettingsUtils = ISettingsUtilsMocks.GetStubSettingsUtils(); + _mockGeneralSettingsUtils = ISettingsUtilsMocks.GetStubSettingsUtils(); + _mockImgResizerSettingsUtils = ISettingsUtilsMocks.GetStubSettingsUtils(); } @@ -44,13 +43,17 @@ namespace ViewModelTests [DataRow("v0.22.0", "settings.json")] public void OriginalFilesModificationTest(string version, string fileName) { - var mockIOProvider = BackCompatTestProperties.GetModuleIOProvider(version, ImageResizerSettings.ModuleName, fileName); - var mockSettingsUtils = new SettingsUtils(mockIOProvider.Object); + var settingPathMock = new Mock(); + + var fileMock = BackCompatTestProperties.GetModuleIOProvider(version, ImageResizerSettings.ModuleName, fileName); + var mockSettingsUtils = new SettingsUtils(fileMock.Object, settingPathMock.Object); + ImageResizerSettings originalSettings = mockSettingsUtils.GetSettings(ImageResizerSettings.ModuleName); - var mockGeneralIOProvider = BackCompatTestProperties.GetGeneralSettingsIOProvider(version); - var mockGeneralSettingsUtils = new SettingsUtils(mockGeneralIOProvider.Object); + var mockGeneralFileMock = BackCompatTestProperties.GetGeneralSettingsIOProvider(version); + var mockGeneralSettingsUtils = new SettingsUtils(mockGeneralFileMock.Object, settingPathMock.Object); GeneralSettings originalGeneralSettings = mockGeneralSettingsUtils.GetSettings(); + var generalSettingsRepository = new BackCompatTestProperties.MockSettingsRepository(mockGeneralSettingsUtils); // Initialise View Model with test Config files @@ -69,8 +72,8 @@ namespace ViewModelTests //Verify that the stub file was used var expectedCallCount = 2; //once via the view model, and once by the test (GetSettings) - BackCompatTestProperties.VerifyModuleIOProviderWasRead(mockIOProvider, ImageResizerSettings.ModuleName, expectedCallCount); - BackCompatTestProperties.VerifyGeneralSettingsIOProviderWasRead(mockGeneralIOProvider, expectedCallCount); + BackCompatTestProperties.VerifyModuleIOProviderWasRead(fileMock, ImageResizerSettings.ModuleName, expectedCallCount); + BackCompatTestProperties.VerifyGeneralSettingsIOProviderWasRead(mockGeneralFileMock, expectedCallCount); } [TestMethod] @@ -85,7 +88,7 @@ namespace ViewModelTests }; // arrange - ImageResizerViewModel viewModel = new ImageResizerViewModel(mockImgResizerSettingsUtils.Object, SettingsRepository.GetInstance(mockGeneralSettingsUtils.Object), SendMockIPCConfigMSG); + ImageResizerViewModel viewModel = new ImageResizerViewModel(_mockImgResizerSettingsUtils.Object, SettingsRepository.GetInstance(_mockGeneralSettingsUtils.Object), SendMockIPCConfigMSG); // act viewModel.IsEnabled = true; @@ -95,16 +98,16 @@ namespace ViewModelTests public void JPEGQualityLevelShouldSetValueToTenWhenSuccessful() { // arrange - var mockIOProvider = IIOProviderMocks.GetMockIOProviderForSaveLoadExists(); - var mockSettingsUtils = new SettingsUtils(mockIOProvider.Object); + var fileSystemMock = new MockFileSystem(); + var mockSettingsUtils = new SettingsUtils(fileSystemMock); Func SendMockIPCConfigMSG = msg => { return 0; }; - ImageResizerViewModel viewModel = new ImageResizerViewModel(mockSettingsUtils, SettingsRepository.GetInstance(mockGeneralSettingsUtils.Object), SendMockIPCConfigMSG); + ImageResizerViewModel viewModel = new ImageResizerViewModel(mockSettingsUtils, SettingsRepository.GetInstance(_mockGeneralSettingsUtils.Object), SendMockIPCConfigMSG); // act viewModel.JPEGQualityLevel = 10; // Assert - viewModel = new ImageResizerViewModel(mockSettingsUtils, SettingsRepository.GetInstance(mockGeneralSettingsUtils.Object), SendMockIPCConfigMSG); + viewModel = new ImageResizerViewModel(mockSettingsUtils, SettingsRepository.GetInstance(_mockGeneralSettingsUtils.Object), SendMockIPCConfigMSG); Assert.AreEqual(10, viewModel.JPEGQualityLevel); } @@ -112,16 +115,16 @@ namespace ViewModelTests public void PngInterlaceOptionShouldSetValueToTenWhenSuccessful() { // arrange - var mockIOProvider = IIOProviderMocks.GetMockIOProviderForSaveLoadExists(); - var mockSettingsUtils = new SettingsUtils(mockIOProvider.Object); + var fileSystemMock = new MockFileSystem(); + var mockSettingsUtils = new SettingsUtils(fileSystemMock); Func SendMockIPCConfigMSG = msg => { return 0; }; - ImageResizerViewModel viewModel = new ImageResizerViewModel(mockSettingsUtils, SettingsRepository.GetInstance(mockGeneralSettingsUtils.Object), SendMockIPCConfigMSG); + ImageResizerViewModel viewModel = new ImageResizerViewModel(mockSettingsUtils, SettingsRepository.GetInstance(_mockGeneralSettingsUtils.Object), SendMockIPCConfigMSG); // act viewModel.PngInterlaceOption = 10; // Assert - viewModel = new ImageResizerViewModel(mockSettingsUtils, SettingsRepository.GetInstance(mockGeneralSettingsUtils.Object), SendMockIPCConfigMSG); + viewModel = new ImageResizerViewModel(mockSettingsUtils, SettingsRepository.GetInstance(_mockGeneralSettingsUtils.Object), SendMockIPCConfigMSG); Assert.AreEqual(10, viewModel.PngInterlaceOption); } @@ -129,16 +132,16 @@ namespace ViewModelTests public void TiffCompressOptionShouldSetValueToTenWhenSuccessful() { // arrange - var mockIOProvider = IIOProviderMocks.GetMockIOProviderForSaveLoadExists(); - var mockSettingsUtils = new SettingsUtils(mockIOProvider.Object); + var fileSystemMock = new MockFileSystem(); + var mockSettingsUtils = new SettingsUtils(fileSystemMock); Func SendMockIPCConfigMSG = msg => { return 0; }; - ImageResizerViewModel viewModel = new ImageResizerViewModel(mockSettingsUtils, SettingsRepository.GetInstance(mockGeneralSettingsUtils.Object), SendMockIPCConfigMSG); + ImageResizerViewModel viewModel = new ImageResizerViewModel(mockSettingsUtils, SettingsRepository.GetInstance(_mockGeneralSettingsUtils.Object), SendMockIPCConfigMSG); // act viewModel.TiffCompressOption = 10; // Assert - viewModel = new ImageResizerViewModel(mockSettingsUtils, SettingsRepository.GetInstance(mockGeneralSettingsUtils.Object), SendMockIPCConfigMSG); + viewModel = new ImageResizerViewModel(mockSettingsUtils, SettingsRepository.GetInstance(_mockGeneralSettingsUtils.Object), SendMockIPCConfigMSG); Assert.AreEqual(10, viewModel.TiffCompressOption); } @@ -146,17 +149,17 @@ namespace ViewModelTests public void FileNameShouldUpdateValueWhenSuccessful() { // arrange - var mockIOProvider = IIOProviderMocks.GetMockIOProviderForSaveLoadExists(); - var mockSettingsUtils = new SettingsUtils(mockIOProvider.Object); + var fileSystemMock = new MockFileSystem(); + var mockSettingsUtils = new SettingsUtils(fileSystemMock); Func SendMockIPCConfigMSG = msg => { return 0; }; - ImageResizerViewModel viewModel = new ImageResizerViewModel(mockSettingsUtils, SettingsRepository.GetInstance(mockGeneralSettingsUtils.Object), SendMockIPCConfigMSG); + ImageResizerViewModel viewModel = new ImageResizerViewModel(mockSettingsUtils, SettingsRepository.GetInstance(_mockGeneralSettingsUtils.Object), SendMockIPCConfigMSG); string expectedValue = "%1 (%3)"; // act viewModel.FileName = expectedValue; // Assert - viewModel = new ImageResizerViewModel(mockSettingsUtils, SettingsRepository.GetInstance(mockGeneralSettingsUtils.Object), SendMockIPCConfigMSG); + viewModel = new ImageResizerViewModel(mockSettingsUtils, SettingsRepository.GetInstance(_mockGeneralSettingsUtils.Object), SendMockIPCConfigMSG); Assert.AreEqual(expectedValue, viewModel.FileName); } @@ -167,6 +170,7 @@ namespace ViewModelTests var settingUtils = ISettingsUtilsMocks.GetStubSettingsUtils(); var expectedSettingsString = new ImageResizerSettings() { Properties = new ImageResizerProperties() { ImageresizerKeepDateModified = new BoolProperty() { Value = true } } }.ToJsonString(); + // Using Ordinal since this is used internally settingUtils.Setup(x => x.SaveSettings( It.Is(content => content.Equals(expectedSettingsString, StringComparison.Ordinal)), It.Is(module => module.Equals(ImageResizerSettings.ModuleName, StringComparison.Ordinal)), @@ -174,7 +178,7 @@ namespace ViewModelTests .Verifiable(); Func SendMockIPCConfigMSG = msg => { return 0; }; - ImageResizerViewModel viewModel = new ImageResizerViewModel(settingUtils.Object, SettingsRepository.GetInstance(mockGeneralSettingsUtils.Object), SendMockIPCConfigMSG); + ImageResizerViewModel viewModel = new ImageResizerViewModel(settingUtils.Object, SettingsRepository.GetInstance(_mockGeneralSettingsUtils.Object), SendMockIPCConfigMSG); // act viewModel.KeepDateModified = true; @@ -187,16 +191,16 @@ namespace ViewModelTests public void EncoderShouldUpdateValueWhenSuccessful() { // arrange - var mockIOProvider = IIOProviderMocks.GetMockIOProviderForSaveLoadExists(); - var mockSettingsUtils = new SettingsUtils(mockIOProvider.Object); + var fileSystemMock = new MockFileSystem(); + var mockSettingsUtils = new SettingsUtils(fileSystemMock); Func SendMockIPCConfigMSG = msg => { return 0; }; - ImageResizerViewModel viewModel = new ImageResizerViewModel(mockSettingsUtils, SettingsRepository.GetInstance(mockGeneralSettingsUtils.Object), SendMockIPCConfigMSG); + ImageResizerViewModel viewModel = new ImageResizerViewModel(mockSettingsUtils, SettingsRepository.GetInstance(_mockGeneralSettingsUtils.Object), SendMockIPCConfigMSG); // act viewModel.Encoder = 3; // Assert - viewModel = new ImageResizerViewModel(mockSettingsUtils, SettingsRepository.GetInstance(mockGeneralSettingsUtils.Object), SendMockIPCConfigMSG); + viewModel = new ImageResizerViewModel(mockSettingsUtils, SettingsRepository.GetInstance(_mockGeneralSettingsUtils.Object), SendMockIPCConfigMSG); Assert.AreEqual("163bcc30-e2e9-4f0b-961d-a3e9fdb788a3", viewModel.EncoderGuid); Assert.AreEqual(3, viewModel.Encoder); } @@ -207,7 +211,7 @@ namespace ViewModelTests // arrange var mockSettingsUtils = ISettingsUtilsMocks.GetStubSettingsUtils(); Func SendMockIPCConfigMSG = msg => { return 0; }; - ImageResizerViewModel viewModel = new ImageResizerViewModel(mockSettingsUtils.Object, SettingsRepository.GetInstance(mockGeneralSettingsUtils.Object), SendMockIPCConfigMSG); + ImageResizerViewModel viewModel = new ImageResizerViewModel(mockSettingsUtils.Object, SettingsRepository.GetInstance(_mockGeneralSettingsUtils.Object), SendMockIPCConfigMSG); int sizeOfOriginalArray = viewModel.Sizes.Count; // act @@ -223,7 +227,7 @@ namespace ViewModelTests // arrange var mockSettingsUtils = ISettingsUtilsMocks.GetStubSettingsUtils(); Func SendMockIPCConfigMSG = msg => { return 0; }; - ImageResizerViewModel viewModel = new ImageResizerViewModel(mockSettingsUtils.Object, SettingsRepository.GetInstance(mockGeneralSettingsUtils.Object), SendMockIPCConfigMSG); + ImageResizerViewModel viewModel = new ImageResizerViewModel(mockSettingsUtils.Object, SettingsRepository.GetInstance(_mockGeneralSettingsUtils.Object), SendMockIPCConfigMSG); int sizeOfOriginalArray = viewModel.Sizes.Count; ImageSize deleteCandidate = viewModel.Sizes.Where(x => x.Id == 0).First(); diff --git a/src/core/Microsoft.PowerToys.Settings.UI.UnitTests/ViewModelTests/PowerLauncherViewModelTest.cs b/src/core/Microsoft.PowerToys.Settings.UI.UnitTests/ViewModelTests/PowerLauncherViewModelTest.cs index 9024e55650..3662d18094 100644 --- a/src/core/Microsoft.PowerToys.Settings.UI.UnitTests/ViewModelTests/PowerLauncherViewModelTest.cs +++ b/src/core/Microsoft.PowerToys.Settings.UI.UnitTests/ViewModelTests/PowerLauncherViewModelTest.cs @@ -10,6 +10,7 @@ using Moq; using Microsoft.PowerToys.Settings.UI.UnitTests.Mocks; using Microsoft.PowerToys.Settings.UI.UnitTests.BackwardsCompatibility; using System.Globalization; +using System.IO.Abstractions; namespace ViewModelTests { @@ -52,13 +53,16 @@ namespace ViewModelTests [DataRow("v0.22.0", "settings.json")] public void OriginalFilesModificationTest(string version, string fileName) { + var settingPathMock = new Mock(); + var mockIOProvider = BackCompatTestProperties.GetModuleIOProvider(version, PowerLauncherSettings.ModuleName, fileName); - var mockSettingsUtils = new SettingsUtils(mockIOProvider.Object); + var mockSettingsUtils = new SettingsUtils(mockIOProvider.Object, settingPathMock.Object); PowerLauncherSettings originalSettings = mockSettingsUtils.GetSettings(PowerLauncherSettings.ModuleName); var mockGeneralIOProvider = BackCompatTestProperties.GetGeneralSettingsIOProvider(version); - var mockGeneralSettingsUtils = new SettingsUtils(mockGeneralIOProvider.Object); + var mockGeneralSettingsUtils = new SettingsUtils(mockGeneralIOProvider.Object, settingPathMock.Object); GeneralSettings originalGeneralSettings = mockGeneralSettingsUtils.GetSettings(); + var generalSettingsRepository = new BackCompatTestProperties.MockSettingsRepository(mockGeneralSettingsUtils); // Initialise View Model with test Config files diff --git a/src/core/Microsoft.PowerToys.Settings.UI.UnitTests/ViewModelTests/PowerPreview.cs b/src/core/Microsoft.PowerToys.Settings.UI.UnitTests/ViewModelTests/PowerPreview.cs index a4b48e63db..c68c973eae 100644 --- a/src/core/Microsoft.PowerToys.Settings.UI.UnitTests/ViewModelTests/PowerPreview.cs +++ b/src/core/Microsoft.PowerToys.Settings.UI.UnitTests/ViewModelTests/PowerPreview.cs @@ -3,7 +3,7 @@ // See the LICENSE file in the project root for more information. using System; -using System.IO; +using System.IO.Abstractions; using System.Text.Json; using Microsoft.PowerToys.Settings.UI.Library; using Microsoft.PowerToys.Settings.UI.Library.ViewModels; @@ -40,13 +40,15 @@ namespace ViewModelTests [DataRow("v0.22.0", "settings.json")] public void OriginalFilesModificationTest(string version, string fileName) { - var mockIOProvider = BackCompatTestProperties.GetModuleIOProvider(version, PowerPreviewSettings.ModuleName, fileName); - var mockSettingsUtils = new SettingsUtils(mockIOProvider.Object); + var settingPathMock = new Mock(); + var fileMock = BackCompatTestProperties.GetModuleIOProvider(version, PowerPreviewSettings.ModuleName, fileName); + + var mockSettingsUtils = new SettingsUtils(fileMock.Object, settingPathMock.Object); PowerPreviewSettings originalSettings = mockSettingsUtils.GetSettings(PowerPreviewSettings.ModuleName); var repository = new BackCompatTestProperties.MockSettingsRepository(mockSettingsUtils); var mockGeneralIOProvider = BackCompatTestProperties.GetGeneralSettingsIOProvider(version); - var mockGeneralSettingsUtils = new SettingsUtils(mockGeneralIOProvider.Object); + var mockGeneralSettingsUtils = new SettingsUtils(mockGeneralIOProvider.Object, settingPathMock.Object); GeneralSettings originalGeneralSettings = mockGeneralSettingsUtils.GetSettings(); var generalSettingsRepository = new BackCompatTestProperties.MockSettingsRepository(mockGeneralSettingsUtils); @@ -62,7 +64,7 @@ namespace ViewModelTests //Verify that the stub file was used var expectedCallCount = 2; //once via the view model, and once by the test (GetSettings) - BackCompatTestProperties.VerifyModuleIOProviderWasRead(mockIOProvider, PowerPreviewSettings.ModuleName, expectedCallCount); + BackCompatTestProperties.VerifyModuleIOProviderWasRead(fileMock, PowerPreviewSettings.ModuleName, expectedCallCount); } diff --git a/src/core/Microsoft.PowerToys.Settings.UI.UnitTests/ViewModelTests/PowerRename.cs b/src/core/Microsoft.PowerToys.Settings.UI.UnitTests/ViewModelTests/PowerRename.cs index 937a163aa4..571d061734 100644 --- a/src/core/Microsoft.PowerToys.Settings.UI.UnitTests/ViewModelTests/PowerRename.cs +++ b/src/core/Microsoft.PowerToys.Settings.UI.UnitTests/ViewModelTests/PowerRename.cs @@ -3,7 +3,7 @@ // See the LICENSE file in the project root for more information. using System; -using System.IO; +using System.IO.Abstractions; using System.Text.Json; using Microsoft.PowerToys.Settings.UI.Library; using Microsoft.PowerToys.Settings.UI.Library.ViewModels; @@ -40,12 +40,16 @@ namespace ViewModelTests [DataRow("v0.22.0", "power-rename-settings.json")] public void OriginalFilesModificationTest(string version, string fileName) { + var settingPathMock = new Mock(); var mockIOProvider = BackCompatTestProperties.GetModuleIOProvider(version, PowerRenameSettings.ModuleName, fileName); - var mockSettingsUtils = new SettingsUtils(mockIOProvider.Object); + + var mockSettingsUtils = new SettingsUtils(mockIOProvider.Object, settingPathMock.Object); PowerRenameLocalProperties originalSettings = mockSettingsUtils.GetSettings(PowerRenameSettings.ModuleName); + var mockGeneralIOProvider = BackCompatTestProperties.GetGeneralSettingsIOProvider(version); - var mockGeneralSettingsUtils = new SettingsUtils(mockGeneralIOProvider.Object); + + var mockGeneralSettingsUtils = new SettingsUtils(mockGeneralIOProvider.Object, settingPathMock.Object); GeneralSettings originalGeneralSettings = mockGeneralSettingsUtils.GetSettings(); var generalSettingsRepository = new BackCompatTestProperties.MockSettingsRepository(mockGeneralSettingsUtils); diff --git a/src/core/Microsoft.PowerToys.Settings.UI.UnitTests/ViewModelTests/ShortcutGuide.cs b/src/core/Microsoft.PowerToys.Settings.UI.UnitTests/ViewModelTests/ShortcutGuide.cs index a6a41fc9d7..53f7a11f06 100644 --- a/src/core/Microsoft.PowerToys.Settings.UI.UnitTests/ViewModelTests/ShortcutGuide.cs +++ b/src/core/Microsoft.PowerToys.Settings.UI.UnitTests/ViewModelTests/ShortcutGuide.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System; -using System.IO; using System.Text.Json; using Microsoft.PowerToys.Settings.UI.Library; using Microsoft.PowerToys.Settings.UI.Library.ViewModels; @@ -30,12 +29,13 @@ namespace ViewModelTests [DataRow("v0.22.0", "settings.json")] public void OriginalFilesModificationTest(string version, string fileName) { + var settingPathMock = new Mock(); var mockIOProvider = BackCompatTestProperties.GetModuleIOProvider(version, ShortcutGuideSettings.ModuleName, fileName); - var mockSettingsUtils = new SettingsUtils(mockIOProvider.Object); + var mockSettingsUtils = new SettingsUtils(mockIOProvider.Object, settingPathMock.Object); ShortcutGuideSettings originalSettings = mockSettingsUtils.GetSettings(ShortcutGuideSettings.ModuleName); var mockGeneralIOProvider = BackCompatTestProperties.GetGeneralSettingsIOProvider(version); - var mockGeneralSettingsUtils = new SettingsUtils(mockGeneralIOProvider.Object); + var mockGeneralSettingsUtils = new SettingsUtils(mockGeneralIOProvider.Object, settingPathMock.Object); GeneralSettings originalGeneralSettings = mockGeneralSettingsUtils.GetSettings(); var generalSettingsRepository = new BackCompatTestProperties.MockSettingsRepository(mockGeneralSettingsUtils); var shortcutSettingsRepository = new BackCompatTestProperties.MockSettingsRepository(mockSettingsUtils); diff --git a/src/core/Microsoft.PowerToys.Settings.UI/Converters/ModuleEnabledToForegroundConverter.cs b/src/core/Microsoft.PowerToys.Settings.UI/Converters/ModuleEnabledToForegroundConverter.cs index 8737b6b4ae..e35908e095 100644 --- a/src/core/Microsoft.PowerToys.Settings.UI/Converters/ModuleEnabledToForegroundConverter.cs +++ b/src/core/Microsoft.PowerToys.Settings.UI/Converters/ModuleEnabledToForegroundConverter.cs @@ -5,7 +5,6 @@ using System; using System.Globalization; using Microsoft.PowerToys.Settings.UI.Library; -using Microsoft.PowerToys.Settings.UI.Library.Utilities; using Windows.UI.Xaml; using Windows.UI.Xaml.Data; using Windows.UI.Xaml.Media; @@ -14,7 +13,7 @@ namespace Microsoft.PowerToys.Settings.UI.Converters { public sealed class ModuleEnabledToForegroundConverter : IValueConverter { - private readonly ISettingsUtils settingsUtils = new SettingsUtils(new SystemIOProvider()); + private readonly ISettingsUtils settingsUtils = new SettingsUtils(); private string selectedTheme = string.Empty; diff --git a/src/core/Microsoft.PowerToys.Settings.UI/Strings/en-us/Resources.resw b/src/core/Microsoft.PowerToys.Settings.UI/Strings/en-us/Resources.resw index 3440beb373..83c908a3ee 100644 --- a/src/core/Microsoft.PowerToys.Settings.UI/Strings/en-us/Resources.resw +++ b/src/core/Microsoft.PowerToys.Settings.UI/Strings/en-us/Resources.resw @@ -163,7 +163,10 @@ Enable Keyboard Manager - Keyboard Manager enable toggle header + + Keyboard Manager enable toggle header + do not loc the Product name. Do you want this feature on / off + Select the profile to display the active key remap and shortcuts @@ -214,6 +217,7 @@ Enable Color Picker + do not loc the Product name. Do you want this feature on / off Change cursor when picking a color @@ -229,6 +233,7 @@ Enable PowerToys Run + do not loc the Product name. Do you want this feature on / off Search & results @@ -311,6 +316,7 @@ Enable FancyZones + do not loc the Product name. Do you want this feature on / off Excluded apps @@ -373,10 +379,12 @@ Give feedback - Module overview + Learn more + This label is there to point people to additional overview for how to use the product Attribution + giving credit to the projects this utility was based on About PowerToys @@ -392,12 +400,15 @@ Report a bug + Report an issue inside powertoys Request a feature + Tell our team what we should build Restart as administrator + running PowerToys as a higher level user, account is typically referred to as an admin / administrator Run at startup @@ -407,9 +418,11 @@ Shell integration + This refers to directly integrating in with Windows Enable PowerRename + do not loc the Product name. Do you want this feature on / off Settings theme @@ -428,12 +441,15 @@ Enable Markdown (.md) preview + Do not loc "Markdown". Do you want this feature on / off Enable SVG (.svg) preview + Do you want this feature on / off Enable SVG (.svg) thumbnails + Do you want this feature on / off These settings allow you to manage your Windows File Explorer custom preview handlers. @@ -464,6 +480,7 @@ Enable Shortcut Guide + do not loc the Product name. Do you want this feature on / off Opacity of background @@ -476,6 +493,7 @@ Enable Image Resizer + do not loc the Product name. Do you want this feature on / off Image Size @@ -768,4 +786,4 @@ Windows color settings Windows refers to the Operating system - \ No newline at end of file + diff --git a/src/core/Microsoft.PowerToys.Settings.UI/Views/ColorPickerPage.xaml.cs b/src/core/Microsoft.PowerToys.Settings.UI/Views/ColorPickerPage.xaml.cs index e27aeb3aaa..6d994eedc2 100644 --- a/src/core/Microsoft.PowerToys.Settings.UI/Views/ColorPickerPage.xaml.cs +++ b/src/core/Microsoft.PowerToys.Settings.UI/Views/ColorPickerPage.xaml.cs @@ -2,6 +2,7 @@ // The Microsoft Corporation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.IO.Abstractions; using Microsoft.PowerToys.Settings.UI.Library; using Microsoft.PowerToys.Settings.UI.Library.Utilities; using Microsoft.PowerToys.Settings.UI.Library.ViewModels; @@ -15,7 +16,7 @@ namespace Microsoft.PowerToys.Settings.UI.Views public ColorPickerPage() { - var settingsUtils = new SettingsUtils(new SystemIOProvider()); + var settingsUtils = new SettingsUtils(); ViewModel = new ColorPickerViewModel(settingsUtils, SettingsRepository.GetInstance(settingsUtils), ShellPage.SendDefaultIPCMessage); DataContext = ViewModel; InitializeComponent(); diff --git a/src/core/Microsoft.PowerToys.Settings.UI/Views/FancyZonesPage.xaml.cs b/src/core/Microsoft.PowerToys.Settings.UI/Views/FancyZonesPage.xaml.cs index bf96e0880d..f8687cfd1c 100644 --- a/src/core/Microsoft.PowerToys.Settings.UI/Views/FancyZonesPage.xaml.cs +++ b/src/core/Microsoft.PowerToys.Settings.UI/Views/FancyZonesPage.xaml.cs @@ -16,7 +16,7 @@ namespace Microsoft.PowerToys.Settings.UI.Views public FancyZonesPage() { InitializeComponent(); - var settingsUtils = new SettingsUtils(new SystemIOProvider()); + var settingsUtils = new SettingsUtils(); ViewModel = new FancyZonesViewModel(SettingsRepository.GetInstance(settingsUtils), SettingsRepository.GetInstance(settingsUtils), ShellPage.SendDefaultIPCMessage); DataContext = ViewModel; } diff --git a/src/core/Microsoft.PowerToys.Settings.UI/Views/GeneralPage.xaml.cs b/src/core/Microsoft.PowerToys.Settings.UI/Views/GeneralPage.xaml.cs index 4f36d529a9..9ee9591d36 100644 --- a/src/core/Microsoft.PowerToys.Settings.UI/Views/GeneralPage.xaml.cs +++ b/src/core/Microsoft.PowerToys.Settings.UI/Views/GeneralPage.xaml.cs @@ -36,7 +36,7 @@ namespace Microsoft.PowerToys.Settings.UI.Views // Load string resources ResourceLoader loader = ResourceLoader.GetForViewIndependentUse(); - var settingsUtils = new SettingsUtils(new SystemIOProvider()); + var settingsUtils = new SettingsUtils(); ViewModel = new GeneralViewModel( SettingsRepository.GetInstance(settingsUtils), diff --git a/src/core/Microsoft.PowerToys.Settings.UI/Views/ImageResizerPage.xaml.cs b/src/core/Microsoft.PowerToys.Settings.UI/Views/ImageResizerPage.xaml.cs index bf85ea0b50..c76eeede5c 100644 --- a/src/core/Microsoft.PowerToys.Settings.UI/Views/ImageResizerPage.xaml.cs +++ b/src/core/Microsoft.PowerToys.Settings.UI/Views/ImageResizerPage.xaml.cs @@ -21,7 +21,7 @@ namespace Microsoft.PowerToys.Settings.UI.Views public ImageResizerPage() { InitializeComponent(); - var settingsUtils = new SettingsUtils(new SystemIOProvider()); + var settingsUtils = new SettingsUtils(); ViewModel = new ImageResizerViewModel(settingsUtils, SettingsRepository.GetInstance(settingsUtils), ShellPage.SendDefaultIPCMessage); DataContext = ViewModel; } diff --git a/src/core/Microsoft.PowerToys.Settings.UI/Views/KeyboardManagerPage.xaml.cs b/src/core/Microsoft.PowerToys.Settings.UI/Views/KeyboardManagerPage.xaml.cs index dde3ecc739..15a01e9d4f 100644 --- a/src/core/Microsoft.PowerToys.Settings.UI/Views/KeyboardManagerPage.xaml.cs +++ b/src/core/Microsoft.PowerToys.Settings.UI/Views/KeyboardManagerPage.xaml.cs @@ -5,7 +5,7 @@ using System; using System.Collections.Generic; using System.Globalization; -using System.IO; +using System.IO.Abstractions; using Microsoft.PowerToys.Settings.UI.Library; using Microsoft.PowerToys.Settings.UI.Library.Utilities; using Microsoft.PowerToys.Settings.UI.Library.ViewModels; @@ -24,7 +24,7 @@ namespace Microsoft.PowerToys.Settings.UI.Views private const string PowerToyName = "Keyboard Manager"; private readonly CoreDispatcher dispatcher; - private readonly FileSystemWatcher watcher; + private readonly IFileSystemWatcher watcher; public KeyboardManagerViewModel ViewModel { get; } @@ -32,7 +32,7 @@ namespace Microsoft.PowerToys.Settings.UI.Views { dispatcher = Window.Current.Dispatcher; - var settingsUtils = new SettingsUtils(new SystemIOProvider()); + var settingsUtils = new SettingsUtils(); ViewModel = new KeyboardManagerViewModel(settingsUtils, SettingsRepository.GetInstance(settingsUtils), ShellPage.SendDefaultIPCMessage, FilterRemapKeysList); watcher = Helper.GetFileWatcher( diff --git a/src/core/Microsoft.PowerToys.Settings.UI/Views/PowerLauncherPage.xaml.cs b/src/core/Microsoft.PowerToys.Settings.UI/Views/PowerLauncherPage.xaml.cs index 59a61ac699..2efd6c7629 100644 --- a/src/core/Microsoft.PowerToys.Settings.UI/Views/PowerLauncherPage.xaml.cs +++ b/src/core/Microsoft.PowerToys.Settings.UI/Views/PowerLauncherPage.xaml.cs @@ -21,7 +21,7 @@ namespace Microsoft.PowerToys.Settings.UI.Views public PowerLauncherPage() { InitializeComponent(); - var settingsUtils = new SettingsUtils(new SystemIOProvider()); + var settingsUtils = new SettingsUtils(); ViewModel = new PowerLauncherViewModel(settingsUtils, SettingsRepository.GetInstance(settingsUtils), ShellPage.SendDefaultIPCMessage, (int)Windows.System.VirtualKey.Space); DataContext = ViewModel; diff --git a/src/core/Microsoft.PowerToys.Settings.UI/Views/PowerPreviewPage.xaml.cs b/src/core/Microsoft.PowerToys.Settings.UI/Views/PowerPreviewPage.xaml.cs index 0e23644bdb..ee760a37e1 100644 --- a/src/core/Microsoft.PowerToys.Settings.UI/Views/PowerPreviewPage.xaml.cs +++ b/src/core/Microsoft.PowerToys.Settings.UI/Views/PowerPreviewPage.xaml.cs @@ -19,7 +19,7 @@ namespace Microsoft.PowerToys.Settings.UI.Views public PowerPreviewPage() { InitializeComponent(); - var settingsUtils = new SettingsUtils(new SystemIOProvider()); + var settingsUtils = new SettingsUtils(); ViewModel = new PowerPreviewViewModel(SettingsRepository.GetInstance(settingsUtils), SettingsRepository.GetInstance(settingsUtils), ShellPage.SendDefaultIPCMessage); DataContext = ViewModel; } diff --git a/src/core/Microsoft.PowerToys.Settings.UI/Views/PowerRenamePage.xaml.cs b/src/core/Microsoft.PowerToys.Settings.UI/Views/PowerRenamePage.xaml.cs index dd8bec2564..c0f9a1b514 100644 --- a/src/core/Microsoft.PowerToys.Settings.UI/Views/PowerRenamePage.xaml.cs +++ b/src/core/Microsoft.PowerToys.Settings.UI/Views/PowerRenamePage.xaml.cs @@ -16,7 +16,7 @@ namespace Microsoft.PowerToys.Settings.UI.Views public PowerRenamePage() { InitializeComponent(); - var settingsUtils = new SettingsUtils(new SystemIOProvider()); + var settingsUtils = new SettingsUtils(); ViewModel = new PowerRenameViewModel(settingsUtils, SettingsRepository.GetInstance(settingsUtils), ShellPage.SendDefaultIPCMessage); DataContext = ViewModel; diff --git a/src/core/Microsoft.PowerToys.Settings.UI/Views/ShortcutGuidePage.xaml.cs b/src/core/Microsoft.PowerToys.Settings.UI/Views/ShortcutGuidePage.xaml.cs index 503b31d8d7..b1ec61624b 100644 --- a/src/core/Microsoft.PowerToys.Settings.UI/Views/ShortcutGuidePage.xaml.cs +++ b/src/core/Microsoft.PowerToys.Settings.UI/Views/ShortcutGuidePage.xaml.cs @@ -17,7 +17,7 @@ namespace Microsoft.PowerToys.Settings.UI.Views { InitializeComponent(); - var settingsUtils = new SettingsUtils(new SystemIOProvider()); + var settingsUtils = new SettingsUtils(); ViewModel = new ShortcutGuideViewModel(SettingsRepository.GetInstance(settingsUtils), SettingsRepository.GetInstance(settingsUtils), ShellPage.SendDefaultIPCMessage); DataContext = ViewModel; } diff --git a/src/core/Microsoft.PowerToys.Settings.UI/loc/ja/src/core/Microsoft.PowerToys.Settings.UI/Strings/en-us/Resources.resw.lcl b/src/core/Microsoft.PowerToys.Settings.UI/loc/ja/src/core/Microsoft.PowerToys.Settings.UI/Strings/en-us/Resources.resw.lcl index 09179c1389..03966f7659 100644 --- a/src/core/Microsoft.PowerToys.Settings.UI/loc/ja/src/core/Microsoft.PowerToys.Settings.UI/Strings/en-us/Resources.resw.lcl +++ b/src/core/Microsoft.PowerToys.Settings.UI/loc/ja/src/core/Microsoft.PowerToys.Settings.UI/Strings/en-us/Resources.resw.lcl @@ -148,6 +148,9 @@ + + + @@ -1483,33 +1486,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1600,15 +1576,6 @@ - - - - - - - - - @@ -1783,7 +1750,7 @@ - + diff --git a/src/core/Microsoft.PowerToys.Settings.UI/loc/sv/src/core/Microsoft.PowerToys.Settings.UI/Strings/en-us/Resources.resw.lcl b/src/core/Microsoft.PowerToys.Settings.UI/loc/sv/src/core/Microsoft.PowerToys.Settings.UI/Strings/en-us/Resources.resw.lcl index 4dc5864958..9eeb7fc5db 100644 --- a/src/core/Microsoft.PowerToys.Settings.UI/loc/sv/src/core/Microsoft.PowerToys.Settings.UI/Strings/en-us/Resources.resw.lcl +++ b/src/core/Microsoft.PowerToys.Settings.UI/loc/sv/src/core/Microsoft.PowerToys.Settings.UI/Strings/en-us/Resources.resw.lcl @@ -148,6 +148,9 @@ + + + @@ -1483,33 +1486,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1600,12 +1576,6 @@ - - - - - - @@ -1736,7 +1706,7 @@ - + @@ -1780,8 +1750,8 @@ - - + + diff --git a/src/core/Microsoft.PowerToys.Settings.UI/loc/tr/src/core/Microsoft.PowerToys.Settings.UI/Strings/en-us/Resources.resw.lcl b/src/core/Microsoft.PowerToys.Settings.UI/loc/tr/src/core/Microsoft.PowerToys.Settings.UI/Strings/en-us/Resources.resw.lcl index 11942a2183..c8ff36ebf0 100644 --- a/src/core/Microsoft.PowerToys.Settings.UI/loc/tr/src/core/Microsoft.PowerToys.Settings.UI/Strings/en-us/Resources.resw.lcl +++ b/src/core/Microsoft.PowerToys.Settings.UI/loc/tr/src/core/Microsoft.PowerToys.Settings.UI/Strings/en-us/Resources.resw.lcl @@ -148,6 +148,9 @@ + + + @@ -1483,33 +1486,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1600,12 +1576,6 @@ - - - - - - @@ -1780,8 +1750,8 @@ - - + + diff --git a/src/modules/colorPicker/ColorPickerUI/ColorPickerUI.csproj b/src/modules/colorPicker/ColorPickerUI/ColorPickerUI.csproj index 3eef221bc0..9126afe98a 100644 --- a/src/modules/colorPicker/ColorPickerUI/ColorPickerUI.csproj +++ b/src/modules/colorPicker/ColorPickerUI/ColorPickerUI.csproj @@ -225,6 +225,9 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all + + 12.2.5 + 2.0.20525 diff --git a/src/modules/colorPicker/ColorPickerUI/Helpers/ColorRepresentationHelper.cs b/src/modules/colorPicker/ColorPickerUI/Helpers/ColorRepresentationHelper.cs index 230d8913c2..1b2294d915 100644 --- a/src/modules/colorPicker/ColorPickerUI/Helpers/ColorRepresentationHelper.cs +++ b/src/modules/colorPicker/ColorPickerUI/Helpers/ColorRepresentationHelper.cs @@ -66,6 +66,7 @@ namespace ColorPicker.Helpers saturation = Math.Round(saturation * 100); lightness = Math.Round(lightness * 100); + // Using InvariantCulture since this is used for color representation return $"hsl({hue.ToString(CultureInfo.InvariantCulture)}" + $", {saturation.ToString(CultureInfo.InvariantCulture)}%" + $", {lightness.ToString(CultureInfo.InvariantCulture)}%)"; @@ -84,6 +85,7 @@ namespace ColorPicker.Helpers saturation = Math.Round(saturation * 100); value = Math.Round(value * 100); + // Using InvariantCulture since this is used for color representation return $"hsv({hue.ToString(CultureInfo.InvariantCulture)}" + $", {saturation.ToString(CultureInfo.InvariantCulture)}%" + $", {value.ToString(CultureInfo.InvariantCulture)}%)"; @@ -103,6 +105,7 @@ namespace ColorPicker.Helpers yellow = Math.Round(yellow * 100); blackKey = Math.Round(blackKey * 100); + // Using InvariantCulture since this is used for color representation return $"cmyk({cyan.ToString(CultureInfo.InvariantCulture)}%" + $", {magenta.ToString(CultureInfo.InvariantCulture)}%" + $", {yellow.ToString(CultureInfo.InvariantCulture)}%" diff --git a/src/modules/colorPicker/ColorPickerUI/Helpers/Logger.cs b/src/modules/colorPicker/ColorPickerUI/Helpers/Logger.cs index 7058a8ff51..56a149eb7d 100644 --- a/src/modules/colorPicker/ColorPickerUI/Helpers/Logger.cs +++ b/src/modules/colorPicker/ColorPickerUI/Helpers/Logger.cs @@ -5,22 +5,24 @@ using System; using System.Diagnostics; using System.Globalization; -using System.IO; +using System.IO.Abstractions; namespace ColorPicker.Helpers { public static class Logger { - private static readonly string ApplicationLogPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "ColorPicker"); + private static readonly IFileSystem _fileSystem = new FileSystem(); + private static readonly string ApplicationLogPath = _fileSystem.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "ColorPicker"); static Logger() { - if (!Directory.Exists(ApplicationLogPath)) + if (!_fileSystem.Directory.Exists(ApplicationLogPath)) { - Directory.CreateDirectory(ApplicationLogPath); + _fileSystem.Directory.CreateDirectory(ApplicationLogPath); } - var logFilePath = Path.Combine(ApplicationLogPath, "Log_" + DateTime.Now.ToString(@"yyyy-MM-dd", CultureInfo.CurrentCulture) + ".txt"); + // Using InvariantCulture since this is used for a log file name + var logFilePath = _fileSystem.Path.Combine(ApplicationLogPath, "Log_" + DateTime.Now.ToString(@"yyyy-MM-dd", CultureInfo.InvariantCulture) + ".txt"); Trace.Listeners.Add(new TextWriterTraceListener(logFilePath)); diff --git a/src/modules/colorPicker/ColorPickerUI/Mouse/CursorManager.cs b/src/modules/colorPicker/ColorPickerUI/Mouse/CursorManager.cs index a523f575a0..7166f881d9 100644 --- a/src/modules/colorPicker/ColorPickerUI/Mouse/CursorManager.cs +++ b/src/modules/colorPicker/ColorPickerUI/Mouse/CursorManager.cs @@ -3,7 +3,7 @@ // See the LICENSE file in the project root for more information. using System; -using System.IO; +using System.IO.Abstractions; using ColorPicker.Helpers; using Microsoft.Win32; @@ -28,11 +28,13 @@ namespace ColorPicker.Mouse [System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.NamingRules", "SA1310:Field names should not contain underscore", Justification = "Interop object")] private const int SPIF_SENDCHANGE = 0x02; + private static readonly IFileSystem _fileSystem = new FileSystem(); + public static void SetColorPickerCursor() { BackupOriginalCursors(); - var colorPickerCursorPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ColorPickerCursorName); + var colorPickerCursorPath = _fileSystem.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ColorPickerCursorName); ChangeCursor(colorPickerCursorPath, ArrowRegistryName); ChangeCursor(colorPickerCursorPath, IBeamRegistryName); } diff --git a/src/modules/colorPicker/ColorPickerUI/Settings/UserSettings.cs b/src/modules/colorPicker/ColorPickerUI/Settings/UserSettings.cs index a1e50f5ec7..3ccea1f1e4 100644 --- a/src/modules/colorPicker/ColorPickerUI/Settings/UserSettings.cs +++ b/src/modules/colorPicker/ColorPickerUI/Settings/UserSettings.cs @@ -5,6 +5,7 @@ using System; using System.ComponentModel.Composition; using System.IO; +using System.IO.Abstractions; using System.Threading; using Microsoft.PowerToys.Settings.UI.Library; using Microsoft.PowerToys.Settings.UI.Library.Utilities; @@ -20,14 +21,14 @@ namespace ColorPicker.Settings private const int MaxNumberOfRetry = 5; [System.Diagnostics.CodeAnalysis.SuppressMessage("CodeQuality", "IDE0052:Remove unread private members", Justification = "Actually, call back is LoadSettingsFromJson")] - private readonly FileSystemWatcher _watcher; + private readonly IFileSystemWatcher _watcher; private readonly object _loadingSettingsLock = new object(); [ImportingConstructor] public UserSettings() { - _settingsUtils = new SettingsUtils(new SystemIOProvider()); + _settingsUtils = new SettingsUtils(); ChangeCursor = new SettingItem(true); ActivationShortcut = new SettingItem(DefaultActivationShortcut); CopiedColorRepresentation = new SettingItem(ColorRepresentationType.HEX); diff --git a/src/modules/colorPicker/UnitTest-ColorPickerUI/Helpers/ColorHelperTest.cs b/src/modules/colorPicker/UnitTest-ColorPickerUI/Helpers/ColorHelperTest.cs index 5f9c867b93..aae56ac7c2 100644 --- a/src/modules/colorPicker/UnitTest-ColorPickerUI/Helpers/ColorHelperTest.cs +++ b/src/modules/colorPicker/UnitTest-ColorPickerUI/Helpers/ColorHelperTest.cs @@ -167,7 +167,7 @@ namespace UnitTest_ColorPickerUI.Helpers { var color = Color.FromArgb(red, green, blue); - Exception? exception = null; + Exception exception = null; try { diff --git a/src/modules/colorPicker/UnitTest-ColorPickerUI/UnitTest-ColorPickerUI.csproj b/src/modules/colorPicker/UnitTest-ColorPickerUI/UnitTest-ColorPickerUI.csproj index c3c3256613..48f90e048e 100644 --- a/src/modules/colorPicker/UnitTest-ColorPickerUI/UnitTest-ColorPickerUI.csproj +++ b/src/modules/colorPicker/UnitTest-ColorPickerUI/UnitTest-ColorPickerUI.csproj @@ -2,20 +2,16 @@ netcoreapp3.1 - UnitTest_ColorPickerUI false - enable - 8.0 - Library + x64 + true - x64 ..\..\..\..\x64\Debug\modules\ColorPicker\UnitTest-ColorPickerUI\ - x64 ..\..\..\..\x64\Release\modules\ColorPicker\UnitTest-ColorPickerUI\ diff --git a/src/modules/fancyzones/editor/FancyZonesEditor/App.xaml.cs b/src/modules/fancyzones/editor/FancyZonesEditor/App.xaml.cs index 7b6d389c4c..751fc6c40a 100644 --- a/src/modules/fancyzones/editor/FancyZonesEditor/App.xaml.cs +++ b/src/modules/fancyzones/editor/FancyZonesEditor/App.xaml.cs @@ -6,6 +6,7 @@ using System; using System.Collections.Generic; using System.Globalization; using System.IO; +using System.IO.Abstractions; using System.Linq; using System.Runtime.InteropServices; using System.Text; @@ -41,6 +42,8 @@ namespace FancyZonesEditor private const string CrashReportDynamicAssemblyTag = "dynamic assembly doesn't have location"; private const string CrashReportLocationNullTag = "location is null or empty"; + private readonly IFileSystem _fileSystem = new FileSystem(); + public Settings ZoneSettings { get; } public App() @@ -157,6 +160,8 @@ namespace FancyZonesEditor sb.AppendLine("## " + CrashReportEnvironmentTag); sb.AppendLine(CrashReportCommandLineTag + Environment.CommandLine); + + // Using InvariantCulture since this is used for a timestamp internally sb.AppendLine(CrashReportTimestampTag + DateTime.Now.ToString(CultureInfo.InvariantCulture)); sb.AppendLine(CrashReportOSVersionTag + Environment.OSVersion.VersionString); sb.AppendLine(CrashReportIntPtrLengthTag + IntPtr.Size); diff --git a/src/modules/fancyzones/editor/FancyZonesEditor/FancyZonesEditor.csproj b/src/modules/fancyzones/editor/FancyZonesEditor/FancyZonesEditor.csproj index 9494995aa5..9f83b03b19 100644 --- a/src/modules/fancyzones/editor/FancyZonesEditor/FancyZonesEditor.csproj +++ b/src/modules/fancyzones/editor/FancyZonesEditor/FancyZonesEditor.csproj @@ -250,6 +250,9 @@ 2.3.0 + + 12.2.5 + 4.7.2 diff --git a/src/modules/fancyzones/editor/FancyZonesEditor/GridEditorWindow.xaml b/src/modules/fancyzones/editor/FancyZonesEditor/GridEditorWindow.xaml index 9e7e74ac27..7c7ad39c71 100644 --- a/src/modules/fancyzones/editor/FancyZonesEditor/GridEditorWindow.xaml +++ b/src/modules/fancyzones/editor/FancyZonesEditor/GridEditorWindow.xaml @@ -166,8 +166,8 @@ - - + + + {{ThemeName}} + PowerToysRun + {{ThemeDisplayName}} + {{BaseColorScheme}} + {{ColorScheme}} + {{PrimaryAccentColor}} + {{IsHighContrast}} + + {{SystemBaseMediumLowColor}} + + + + + + + + + + + + + + + + + {{ScrollBarThumbPointerOver}} + {{ScrollBarThumbPointerPressed}} + + {{ScrollBarBackgroundPointerOver}} + + + {{ScrollBarLineButtonForegroundPointerOver}} + {{ScrollBarLineButtonForegroundPointerPressed}} + + + {{ScrollBarLineButtonBackgroundPointerOver}} + {{ScrollBarLineButtonBackgroundPointerPressed}} + + + + + \ No newline at end of file diff --git a/src/modules/launcher/Wox.Plugin/Logger/Log.cs b/src/modules/launcher/Wox.Plugin/Logger/Log.cs index 00bebead1f..76fedeac68 100644 --- a/src/modules/launcher/Wox.Plugin/Logger/Log.cs +++ b/src/modules/launcher/Wox.Plugin/Logger/Log.cs @@ -3,7 +3,7 @@ // See the LICENSE file in the project root for more information. using System; -using System.IO; +using System.IO.Abstractions; using System.Runtime.CompilerServices; using NLog; using NLog.Config; @@ -13,6 +13,10 @@ namespace Wox.Plugin.Logger { public static class Log { + private static readonly IFileSystem FileSystem = new FileSystem(); + private static readonly IPath Path = FileSystem.Path; + private static readonly IDirectory Directory = FileSystem.Directory; + public const string DirectoryName = "Logs"; public static string CurrentLogDirectory { get; } diff --git a/src/modules/launcher/Wox.Plugin/PluginMetadata.cs b/src/modules/launcher/Wox.Plugin/PluginMetadata.cs index 657dfe26ba..e4cf311dde 100644 --- a/src/modules/launcher/Wox.Plugin/PluginMetadata.cs +++ b/src/modules/launcher/Wox.Plugin/PluginMetadata.cs @@ -4,7 +4,7 @@ using System; using System.Collections.Generic; -using System.IO; +using System.IO.Abstractions; using Newtonsoft.Json; namespace Wox.Plugin @@ -12,6 +12,9 @@ namespace Wox.Plugin [JsonObject(MemberSerialization.OptOut)] public class PluginMetadata : BaseModel { + private static readonly IFileSystem FileSystem = new FileSystem(); + private static readonly IPath Path = FileSystem.Path; + private string _pluginDirectory; private List _actionKeywords; diff --git a/src/modules/launcher/Wox.Plugin/Result.cs b/src/modules/launcher/Wox.Plugin/Result.cs index 2bcae0d53d..422331840f 100644 --- a/src/modules/launcher/Wox.Plugin/Result.cs +++ b/src/modules/launcher/Wox.Plugin/Result.cs @@ -5,7 +5,7 @@ using System; using System.Collections.Generic; using System.Globalization; -using System.IO; +using System.IO.Abstractions; using System.Windows; using System.Windows.Media; @@ -13,6 +13,9 @@ namespace Wox.Plugin { public class Result { + private static readonly IFileSystem FileSystem = new FileSystem(); + private static readonly IPath Path = FileSystem.Path; + private string _title; private ToolTipData _toolTipData; private string _pluginDirectory; diff --git a/src/modules/launcher/Wox.Plugin/SharedCommands/FilesFolders.cs b/src/modules/launcher/Wox.Plugin/SharedCommands/FilesFolders.cs deleted file mode 100644 index f68c39c655..0000000000 --- a/src/modules/launcher/Wox.Plugin/SharedCommands/FilesFolders.cs +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright (c) Microsoft Corporation -// The Microsoft Corporation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Globalization; -using System.IO; -using System.Reflection; -using Wox.Plugin.Logger; -using Wox.Plugin.Properties; - -namespace Wox.Plugin.SharedCommands -{ - public static class FilesFolders - { - [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "Suppressing this to enable FxCop. We are logging the exception, and going forward general exceptions should not be caught")] - public static void Copy(this string sourcePath, string targetPath) - { - // Get the subdirectories for the specified directory. - DirectoryInfo dir = new DirectoryInfo(sourcePath); - - if (!dir.Exists) - { - throw new DirectoryNotFoundException( - "Source directory does not exist or could not be found: " - + sourcePath); - } - - try - { - DirectoryInfo[] dirs = dir.GetDirectories(); - - // If the destination directory doesn't exist, create it. - if (!Directory.Exists(targetPath)) - { - Directory.CreateDirectory(targetPath); - } - - // Get the files in the directory and copy them to the new location. - FileInfo[] files = dir.GetFiles(); - foreach (FileInfo file in files) - { - string temppath = Path.Combine(targetPath, file.Name); - file.CopyTo(temppath, false); - } - - // Recursively copy subdirectories by calling itself on each subdirectory until there are no more to copy - foreach (DirectoryInfo subdir in dirs) - { - string temppath = Path.Combine(targetPath, subdir.Name); - Copy(subdir.FullName, temppath); - } - } -#pragma warning disable CS0168 // Variable is declared but never used. Due to #if debug vs release statement - catch (Exception e) -#pragma warning restore CS0168 // Variable is declared but never used - { - string error = $"Copying path {targetPath} has failed"; - Log.Exception(error, e, MethodBase.GetCurrentMethod().DeclaringType); -#if DEBUG - throw; -#else - // Using CurrentCulture since this is user facing - System.Windows.MessageBox.Show(string.Format(CultureInfo.CurrentCulture, Resources.filesfolder_copy_failed, targetPath)); - RemoveFolder(targetPath); -#endif - } - } - - [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "Suppressing this to enable FxCop. We are logging the exception, and going forward general exceptions should not be caught")] - public static bool VerifyBothFolderFilesEqual(this string fromPath, string toPath) - { - try - { - var fromDir = new DirectoryInfo(fromPath); - var toDir = new DirectoryInfo(toPath); - - if (fromDir.GetFiles("*", SearchOption.AllDirectories).Length != toDir.GetFiles("*", SearchOption.AllDirectories).Length) - { - return false; - } - - if (fromDir.GetDirectories("*", SearchOption.AllDirectories).Length != toDir.GetDirectories("*", SearchOption.AllDirectories).Length) - { - return false; - } - - return true; - } -#pragma warning disable CS0168 // Variable is declared but never used. Due to #if debug vs release statement - catch (Exception e) -#pragma warning restore CS0168 // Variable is declared but never used - { - string error = $"Unable to verify folders and files between {fromPath} and {toPath}"; - Log.Exception(error, e, MethodBase.GetCurrentMethod().DeclaringType); -#if DEBUG - throw; -#else - // Using CurrentCulture since this is user facing - System.Windows.MessageBox.Show(string.Format(CultureInfo.CurrentCulture, Resources.filesfolder_verifybothfolderfilesequal_failed, fromPath, toPath)); - return false; -#endif - } - } - - [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "Suppressing this to enable FxCop. We are logging the exception, and going forward general exceptions should not be caught")] - public static void RemoveFolder(this string path) - { - try - { - if (Directory.Exists(path)) - { - Directory.Delete(path, true); - } - } -#pragma warning disable CS0168 // Variable is declared but never used. Due to #if debug vs release statement - catch (Exception e) -#pragma warning restore CS0168 // Variable is declared but never used - { - string error = $"Not able to delete folder {path}"; - Log.Exception(error, e, MethodBase.GetCurrentMethod().DeclaringType); -#if DEBUG - throw; -#else - // Using CurrentCulture since this is user facing - System.Windows.MessageBox.Show(string.Format(CultureInfo.CurrentCulture, Resources.filesfolder_removefolder_failed, path)); -#endif - } - } - } -} diff --git a/src/modules/launcher/Wox.Plugin/SharedCommands/SearchWeb.cs b/src/modules/launcher/Wox.Plugin/SharedCommands/SearchWeb.cs deleted file mode 100644 index 224c7a830d..0000000000 --- a/src/modules/launcher/Wox.Plugin/SharedCommands/SearchWeb.cs +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright (c) Microsoft Corporation -// The Microsoft Corporation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Diagnostics; -using System.IO; -using System.Linq; - -namespace Wox.Plugin.SharedCommands -{ - public static class SearchWeb - { - /// - /// Opens search in a new browser. If no browser path is passed in then Chrome is used. - /// Leave browser path blank to use Chrome. - /// - public static void NewBrowserWindow(this Uri url, string browserPath) - { - if (url == null) - { - throw new ArgumentNullException(nameof(url)); - } - - var browserExecutableName = browserPath? - .Split(new[] { Path.DirectorySeparatorChar }, StringSplitOptions.None) - .Last(); - - var browser = string.IsNullOrEmpty(browserExecutableName) ? "chrome" : browserPath; - - // Internet Explorer will open url in new browser window, and does not take the --new-window parameter - var browserArguments = browserExecutableName == "iexplore.exe" ? url.AbsoluteUri : "--new-window " + url.AbsoluteUri; - - try - { - Process.Start(browser, browserArguments); - } - catch (System.ComponentModel.Win32Exception) - { - var psi = new ProcessStartInfo - { - FileName = url.AbsoluteUri, - UseShellExecute = true, - }; - Process.Start(psi); - } - } - - /// - /// Opens search as a tab in the default browser chosen in Windows settings. - /// - public static void NewTabInBrowser(this Uri url, string browserPath) - { - if (url == null) - { - throw new ArgumentNullException(nameof(url)); - } - - try - { - if (!string.IsNullOrEmpty(browserPath)) - { - Process.Start(browserPath, url.AbsoluteUri); - } - else - { - Process.Start(url.AbsoluteUri); - } - } - - // This error may be thrown for Process.Start(browserPath, url) - catch (System.ComponentModel.Win32Exception) - { - Process.Start(url.AbsoluteUri); - } - } - } -} diff --git a/src/modules/launcher/Wox.Plugin/ThemeManager.cs b/src/modules/launcher/Wox.Plugin/ThemeManager.cs index 55b3cdcc06..a8c19bba7c 100644 --- a/src/modules/launcher/Wox.Plugin/ThemeManager.cs +++ b/src/modules/launcher/Wox.Plugin/ThemeManager.cs @@ -1,11 +1,10 @@ -// Copyright (c) Microsoft Corporation +// Copyright (c) Microsoft Corporation // The Microsoft Corporation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. using System; using System.Linq; using System.Windows; -using MahApps.Metro.Theming; using ManagedCommon; using Microsoft.Win32; @@ -40,31 +39,35 @@ namespace Wox.Plugin ControlzEx.Theming.ThemeManager.Current.AddLibraryTheme( new ControlzEx.Theming.LibraryTheme( highContrastOneThemeUri, - MahAppsLibraryThemeProvider.DefaultInstance)); + CustomLibraryThemeProvider.DefaultInstance)); ControlzEx.Theming.ThemeManager.Current.AddLibraryTheme( new ControlzEx.Theming.LibraryTheme( highContrastTwoThemeUri, - MahAppsLibraryThemeProvider.DefaultInstance)); + CustomLibraryThemeProvider.DefaultInstance)); ControlzEx.Theming.ThemeManager.Current.AddLibraryTheme( new ControlzEx.Theming.LibraryTheme( highContrastBlackThemeUri, - MahAppsLibraryThemeProvider.DefaultInstance)); + CustomLibraryThemeProvider.DefaultInstance)); ControlzEx.Theming.ThemeManager.Current.AddLibraryTheme( new ControlzEx.Theming.LibraryTheme( highContrastWhiteThemeUri, - MahAppsLibraryThemeProvider.DefaultInstance)); + CustomLibraryThemeProvider.DefaultInstance)); ControlzEx.Theming.ThemeManager.Current.AddLibraryTheme( new ControlzEx.Theming.LibraryTheme( lightThemeUri, - MahAppsLibraryThemeProvider.DefaultInstance)); + CustomLibraryThemeProvider.DefaultInstance)); ControlzEx.Theming.ThemeManager.Current.AddLibraryTheme( new ControlzEx.Theming.LibraryTheme( darkThemeUri, - MahAppsLibraryThemeProvider.DefaultInstance)); + CustomLibraryThemeProvider.DefaultInstance)); - ResetTheme(); - ControlzEx.Theming.ThemeManager.Current.ThemeSyncMode = ControlzEx.Theming.ThemeSyncMode.SyncAll; ControlzEx.Theming.ThemeManager.Current.ThemeChanged += Current_ThemeChanged; + + // Currently there is an issue in ControlzEx, so we must use SyncAll to sync also HighContrast themes. + // We can change this after using next release. + ControlzEx.Theming.ThemeManager.Current.ThemeSyncMode = ControlzEx.Theming.ThemeSyncMode.SyncAll; + + ControlzEx.Theming.ThemeManager.Current.SyncTheme(); } public Theme GetCurrentTheme() @@ -119,22 +122,22 @@ namespace Wox.Plugin else if (theme == Theme.HighContrastOne) { currentTheme = Theme.HighContrastOne; - ControlzEx.Theming.ThemeManager.Current.ChangeTheme(_app, HighContrastOneTheme); + ControlzEx.Theming.ThemeManager.Current.ChangeTheme(_app, HighContrastOneTheme, true); } else if (theme == Theme.HighContrastTwo) { currentTheme = Theme.HighContrastTwo; - ControlzEx.Theming.ThemeManager.Current.ChangeTheme(_app, HighContrastTwoTheme); + ControlzEx.Theming.ThemeManager.Current.ChangeTheme(_app, HighContrastTwoTheme, true); } else if (theme == Theme.HighContrastWhite) { currentTheme = Theme.HighContrastWhite; - ControlzEx.Theming.ThemeManager.Current.ChangeTheme(_app, HighContrastWhiteTheme); + ControlzEx.Theming.ThemeManager.Current.ChangeTheme(_app, HighContrastWhiteTheme, true); } else if (theme == Theme.HighContrastBlack) { currentTheme = Theme.HighContrastBlack; - ControlzEx.Theming.ThemeManager.Current.ChangeTheme(_app, HighContrastBlackTheme); + ControlzEx.Theming.ThemeManager.Current.ChangeTheme(_app, HighContrastBlackTheme, true); } else if (theme == Theme.Light) { @@ -157,7 +160,15 @@ namespace Wox.Plugin private void Current_ThemeChanged(object sender, ControlzEx.Theming.ThemeChangedEventArgs e) { - ResetTheme(); + ControlzEx.Theming.ThemeManager.Current.ThemeChanged -= Current_ThemeChanged; + try + { + ResetTheme(); + } + finally + { + ControlzEx.Theming.ThemeManager.Current.ThemeChanged += Current_ThemeChanged; + } } protected virtual void Dispose(bool disposing) diff --git a/src/modules/launcher/Wox.Plugin/Wox.Plugin.csproj b/src/modules/launcher/Wox.Plugin/Wox.Plugin.csproj index 8d9c037483..b92c794657 100644 --- a/src/modules/launcher/Wox.Plugin/Wox.Plugin.csproj +++ b/src/modules/launcher/Wox.Plugin/Wox.Plugin.csproj @@ -49,6 +49,15 @@ true + + $(DefaultItemExcludes);**/*.Template.xaml + + + + + + + @@ -67,7 +76,6 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - all diff --git a/src/modules/launcher/Wox.Plugin/loc/cs/src/modules/launcher/Wox.Plugin/Properties/Resources.resx.lcl b/src/modules/launcher/Wox.Plugin/loc/cs/src/modules/launcher/Wox.Plugin/Properties/Resources.resx.lcl index 20aa817c87..894b58408f 100644 --- a/src/modules/launcher/Wox.Plugin/loc/cs/src/modules/launcher/Wox.Plugin/Properties/Resources.resx.lcl +++ b/src/modules/launcher/Wox.Plugin/loc/cs/src/modules/launcher/Wox.Plugin/Properties/Resources.resx.lcl @@ -13,29 +13,29 @@ + + + - - - + + + - - - + + + - - - diff --git a/src/modules/launcher/Wox.Plugin/loc/de/src/modules/launcher/Wox.Plugin/Properties/Resources.resx.lcl b/src/modules/launcher/Wox.Plugin/loc/de/src/modules/launcher/Wox.Plugin/Properties/Resources.resx.lcl index f2c7a84fc1..e8433ea738 100644 --- a/src/modules/launcher/Wox.Plugin/loc/de/src/modules/launcher/Wox.Plugin/Properties/Resources.resx.lcl +++ b/src/modules/launcher/Wox.Plugin/loc/de/src/modules/launcher/Wox.Plugin/Properties/Resources.resx.lcl @@ -13,29 +13,29 @@ + + + - - - + + + - - - + + + - - - diff --git a/src/modules/launcher/Wox.Plugin/loc/es/src/modules/launcher/Wox.Plugin/Properties/Resources.resx.lcl b/src/modules/launcher/Wox.Plugin/loc/es/src/modules/launcher/Wox.Plugin/Properties/Resources.resx.lcl index 9e743b6bd6..d52642fde1 100644 --- a/src/modules/launcher/Wox.Plugin/loc/es/src/modules/launcher/Wox.Plugin/Properties/Resources.resx.lcl +++ b/src/modules/launcher/Wox.Plugin/loc/es/src/modules/launcher/Wox.Plugin/Properties/Resources.resx.lcl @@ -13,29 +13,29 @@ + + + - - - + + + - - - + + + - - - diff --git a/src/modules/launcher/Wox.Plugin/loc/fr/src/modules/launcher/Wox.Plugin/Properties/Resources.resx.lcl b/src/modules/launcher/Wox.Plugin/loc/fr/src/modules/launcher/Wox.Plugin/Properties/Resources.resx.lcl index e67764b6e2..6f087f90e3 100644 --- a/src/modules/launcher/Wox.Plugin/loc/fr/src/modules/launcher/Wox.Plugin/Properties/Resources.resx.lcl +++ b/src/modules/launcher/Wox.Plugin/loc/fr/src/modules/launcher/Wox.Plugin/Properties/Resources.resx.lcl @@ -13,29 +13,29 @@ + + + - - - + + + - - - + + + - - - diff --git a/src/modules/launcher/Wox.Plugin/loc/hu/src/modules/launcher/Wox.Plugin/Properties/Resources.resx.lcl b/src/modules/launcher/Wox.Plugin/loc/hu/src/modules/launcher/Wox.Plugin/Properties/Resources.resx.lcl index ca61fd5acc..338d7a142d 100644 --- a/src/modules/launcher/Wox.Plugin/loc/hu/src/modules/launcher/Wox.Plugin/Properties/Resources.resx.lcl +++ b/src/modules/launcher/Wox.Plugin/loc/hu/src/modules/launcher/Wox.Plugin/Properties/Resources.resx.lcl @@ -13,29 +13,29 @@ + + + - - - + + + - - - + + + - - - diff --git a/src/modules/launcher/Wox.Plugin/loc/ja/src/modules/launcher/Wox.Plugin/Properties/Resources.resx.lcl b/src/modules/launcher/Wox.Plugin/loc/ja/src/modules/launcher/Wox.Plugin/Properties/Resources.resx.lcl index 9c053516cc..b458bb4d8f 100644 --- a/src/modules/launcher/Wox.Plugin/loc/ja/src/modules/launcher/Wox.Plugin/Properties/Resources.resx.lcl +++ b/src/modules/launcher/Wox.Plugin/loc/ja/src/modules/launcher/Wox.Plugin/Properties/Resources.resx.lcl @@ -13,29 +13,29 @@ + + + - - - + + + - - - + + + - - - diff --git a/src/modules/launcher/Wox.Plugin/loc/nl/src/modules/launcher/Wox.Plugin/Properties/Resources.resx.lcl b/src/modules/launcher/Wox.Plugin/loc/nl/src/modules/launcher/Wox.Plugin/Properties/Resources.resx.lcl index acad4295fc..e8644aaba3 100644 --- a/src/modules/launcher/Wox.Plugin/loc/nl/src/modules/launcher/Wox.Plugin/Properties/Resources.resx.lcl +++ b/src/modules/launcher/Wox.Plugin/loc/nl/src/modules/launcher/Wox.Plugin/Properties/Resources.resx.lcl @@ -13,29 +13,29 @@ + + + - - - + + + - - - + + + - - - diff --git a/src/modules/launcher/Wox.Plugin/loc/pt-BR/src/modules/launcher/Wox.Plugin/Properties/Resources.resx.lcl b/src/modules/launcher/Wox.Plugin/loc/pt-BR/src/modules/launcher/Wox.Plugin/Properties/Resources.resx.lcl index e455f4b6fb..6508d57795 100644 --- a/src/modules/launcher/Wox.Plugin/loc/pt-BR/src/modules/launcher/Wox.Plugin/Properties/Resources.resx.lcl +++ b/src/modules/launcher/Wox.Plugin/loc/pt-BR/src/modules/launcher/Wox.Plugin/Properties/Resources.resx.lcl @@ -13,29 +13,29 @@ + + + - - - + + + - - - + + + - - - diff --git a/src/modules/launcher/Wox.Plugin/loc/ru/src/modules/launcher/Wox.Plugin/Properties/Resources.resx.lcl b/src/modules/launcher/Wox.Plugin/loc/ru/src/modules/launcher/Wox.Plugin/Properties/Resources.resx.lcl index 492d44b6b1..1a6c046d1b 100644 --- a/src/modules/launcher/Wox.Plugin/loc/ru/src/modules/launcher/Wox.Plugin/Properties/Resources.resx.lcl +++ b/src/modules/launcher/Wox.Plugin/loc/ru/src/modules/launcher/Wox.Plugin/Properties/Resources.resx.lcl @@ -13,29 +13,29 @@ + + + - - - + + + - - - + + + - - - diff --git a/src/modules/launcher/Wox.Plugin/loc/tr/src/modules/launcher/Wox.Plugin/Properties/Resources.resx.lcl b/src/modules/launcher/Wox.Plugin/loc/tr/src/modules/launcher/Wox.Plugin/Properties/Resources.resx.lcl index 6c57456e62..2ccdcfdb1c 100644 --- a/src/modules/launcher/Wox.Plugin/loc/tr/src/modules/launcher/Wox.Plugin/Properties/Resources.resx.lcl +++ b/src/modules/launcher/Wox.Plugin/loc/tr/src/modules/launcher/Wox.Plugin/Properties/Resources.resx.lcl @@ -13,29 +13,29 @@ + + + - - - + + + - - - + + + - - - diff --git a/src/modules/launcher/Wox.Plugin/loc/zh-Hans/src/modules/launcher/Wox.Plugin/Properties/Resources.resx.lcl b/src/modules/launcher/Wox.Plugin/loc/zh-Hans/src/modules/launcher/Wox.Plugin/Properties/Resources.resx.lcl index 5d0e91b07e..49c1ef83da 100644 --- a/src/modules/launcher/Wox.Plugin/loc/zh-Hans/src/modules/launcher/Wox.Plugin/Properties/Resources.resx.lcl +++ b/src/modules/launcher/Wox.Plugin/loc/zh-Hans/src/modules/launcher/Wox.Plugin/Properties/Resources.resx.lcl @@ -13,29 +13,29 @@ + + + - - - + + + - - - + + + - - - diff --git a/src/modules/launcher/Wox.Test/Plugins/WindowsIndexerTest.cs b/src/modules/launcher/Wox.Test/Plugins/WindowsIndexerTest.cs index 8d9a2b5155..b9ca054e78 100644 --- a/src/modules/launcher/Wox.Test/Plugins/WindowsIndexerTest.cs +++ b/src/modules/launcher/Wox.Test/Plugins/WindowsIndexerTest.cs @@ -380,6 +380,8 @@ namespace Wox.Test.Plugins // Assert string expectedSqlQuery = "SELECT TOP 30 \"System.ItemUrl\", \"System.FileName\", \"System.FileAttributes\" FROM \"SystemIndex\" WHERE (CONTAINS(System.FileName,'\"abcd.*\"',1033)) AND scope='file:' ORDER BY System.DateModified DESC"; + + // Using InvariantCultureIgnoreCase since this relates to sql code in string form Assert.IsFalse(simplifiedSqlQuery.Equals(sqlQuery, StringComparison.InvariantCultureIgnoreCase)); Assert.IsTrue(simplifiedSqlQuery.Equals(expectedSqlQuery, StringComparison.InvariantCultureIgnoreCase)); } @@ -394,6 +396,7 @@ namespace Wox.Test.Plugins var simplifiedSqlQuery = WindowsSearchAPI.SimplifyQuery(sqlQuery); // Assert + // Using InvariantCultureIgnoreCase since this relates to sql code in string form Assert.IsTrue(simplifiedSqlQuery.Equals(sqlQuery, StringComparison.InvariantCultureIgnoreCase)); } @@ -408,6 +411,8 @@ namespace Wox.Test.Plugins // Assert string expectedSqlQuery = "SELECT TOP 30 \"System.ItemUrl\", \"System.FileName\", \"System.FileAttributes\", \"System.FileExtension\" FROM \"SystemIndex\" WHERE (CONTAINS(System.FileName,'\"ab.*\"',1033)) AND (CONTAINS(System.FileName,'\".cd*\"',1033)) AND scope='file:' ORDER BY System.DateModified DESC"; + + // Using InvariantCultureIgnoreCase since this relates to sql code in string form Assert.IsFalse(simplifiedSqlQuery.Equals(sqlQuery, StringComparison.InvariantCultureIgnoreCase)); Assert.IsTrue(simplifiedSqlQuery.Equals(expectedSqlQuery, StringComparison.InvariantCultureIgnoreCase)); } @@ -423,6 +428,8 @@ namespace Wox.Test.Plugins // Assert string expectedSqlQuery = "SELECT TOP 30 \"System.ItemUrl\", \"System.FileName\", \"System.FileAttributes\" FROM \"SystemIndex\" WHERE (CONTAINS(System.FileName,'\"'ab.cd'*\"',1033)) AND scope='file:' ORDER BY System.DateModified DESC"; + + // Using InvariantCultureIgnoreCase since this relates to sql code in string form Assert.IsFalse(simplifiedSqlQuery.Equals(sqlQuery, StringComparison.InvariantCultureIgnoreCase)); Assert.IsTrue(simplifiedSqlQuery.Equals(expectedSqlQuery, StringComparison.InvariantCultureIgnoreCase)); } diff --git a/src/modules/powerrename/ui/PowerRenameUI.base.rc b/src/modules/powerrename/ui/PowerRenameUI.base.rc index 1338197c5c..0369a50812 100644 Binary files a/src/modules/powerrename/ui/PowerRenameUI.base.rc and b/src/modules/powerrename/ui/PowerRenameUI.base.rc differ diff --git a/src/modules/powerrename/ui/PowerRenameUI.cpp b/src/modules/powerrename/ui/PowerRenameUI.cpp index 2edf08544d..83abdd4850 100644 --- a/src/modules/powerrename/ui/PowerRenameUI.cpp +++ b/src/modules/powerrename/ui/PowerRenameUI.cpp @@ -63,7 +63,8 @@ RepositionMap g_repositionMap[] = { { IDC_EDIT_SEARCHFOR, Reposition_Width }, { IDC_EDIT_REPLACEWITH, Reposition_Width }, { IDC_LIST_PREVIEW, Reposition_Width | Reposition_Height }, - { IDC_STATUS_MESSAGE, Reposition_Y }, + { IDC_STATUS_MESSAGE_SELECTED, Reposition_Y }, + { IDC_STATUS_MESSAGE_RENAMING, Reposition_Y }, { ID_RENAME, Reposition_X | Reposition_Y }, { ID_ABOUT, Reposition_X | Reposition_Y }, { IDCANCEL, Reposition_X | Reposition_Y } @@ -679,7 +680,8 @@ void CPowerRenameUI::_InitDlgText() UpdateDlgControl(m_hwnd, IDCANCEL, IDS_CANCEL_BUTTON); UpdateDlgControl(m_hwnd, IDC_SEARCH_FOR, IDS_SEARCH_FOR); UpdateDlgControl(m_hwnd, IDC_REPLACE_WITH, IDS_REPLACE_WITH); - UpdateDlgControl(m_hwnd, IDC_STATUS_MESSAGE, IDS_ITEMS_SELECTED); + UpdateDlgControl(m_hwnd, IDC_STATUS_MESSAGE_SELECTED, IDS_ITEMS_SELECTED); + UpdateDlgControl(m_hwnd, IDC_STATUS_MESSAGE_RENAMING, IDS_ITEMS_RENAMING); UpdateDlgControl(m_hwnd, IDC_OPTIONSGROUP, IDS_OPTIONS); UpdateDlgControl(m_hwnd, IDC_PREVIEWGROUP, IDS_PREVIEW); UpdateDlgControl(m_hwnd, IDC_SEARCHREPLACEGROUP, IDS_RENAME_CRITERIA); @@ -868,8 +870,11 @@ void CPowerRenameUI::_MoveControl(_In_ DWORD id, _In_ DWORD repositionFlags) width = mainWindowWidth - static_cast(m_itemsPositioning.listPreviewWidthDiff * scale); height = mainWindowHeight - static_cast(m_itemsPositioning.listPreviewHeightDiff * scale); break; - case IDC_STATUS_MESSAGE: - y = mainWindowHeight - static_cast(m_itemsPositioning.statusMessageYDiff * scale); + case IDC_STATUS_MESSAGE_SELECTED: + y = mainWindowHeight - static_cast(m_itemsPositioning.statusMessageSelectedYDiff * scale); + break; + case IDC_STATUS_MESSAGE_RENAMING: + y = mainWindowHeight - static_cast(m_itemsPositioning.statusMessageRenamingYDiff * scale); break; case ID_RENAME: x = mainWindowWidth - static_cast(m_itemsPositioning.renameButtonXDiff * scale); @@ -1000,12 +1005,17 @@ void CPowerRenameUI::_UpdateCounts() m_renamingCount = renamingCount; // Update selected and rename count label - wchar_t countsLabelFormat[100] = { 0 }; - LoadString(g_hInst, IDS_COUNTSLABELFMT, countsLabelFormat, ARRAYSIZE(countsLabelFormat)); + wchar_t countsLabelFormatSelected[100] = { 0 }; + wchar_t countsLabelFormatRenaming[100] = { 0 }; + LoadString(g_hInst, IDS_COUNTSLABELSELECTEDFMT, countsLabelFormatSelected, ARRAYSIZE(countsLabelFormatSelected)); + LoadString(g_hInst, IDS_COUNTSLABELRENAMINGFMT, countsLabelFormatRenaming, ARRAYSIZE(countsLabelFormatRenaming)); - wchar_t countsLabel[100] = { 0 }; - StringCchPrintf(countsLabel, ARRAYSIZE(countsLabel), countsLabelFormat, selectedCount, renamingCount); - SetDlgItemText(m_hwnd, IDC_STATUS_MESSAGE, countsLabel); + wchar_t countsLabelSelected[100] = { 0 }; + wchar_t countsLabelRenaming[100] = { 0 }; + StringCchPrintf(countsLabelSelected, ARRAYSIZE(countsLabelSelected), countsLabelFormatSelected, selectedCount); + StringCchPrintf(countsLabelRenaming, ARRAYSIZE(countsLabelRenaming), countsLabelFormatRenaming, renamingCount); + SetDlgItemText(m_hwnd, IDC_STATUS_MESSAGE_SELECTED, countsLabelSelected); + SetDlgItemText(m_hwnd, IDC_STATUS_MESSAGE_RENAMING, countsLabelRenaming); // Update Rename button state EnableWindow(GetDlgItem(m_hwnd, ID_RENAME), (renamingCount > 0)); @@ -1039,8 +1049,11 @@ void CPowerRenameUI::_CollectItemPosition(_In_ DWORD id) m_itemsPositioning.listPreviewWidthDiff = m_initialWidth - itemWidth; m_itemsPositioning.listPreviewHeightDiff = m_initialHeight - itemHeight; break; - case IDC_STATUS_MESSAGE: - m_itemsPositioning.statusMessageYDiff = m_initialHeight - rcWindow.top; + case IDC_STATUS_MESSAGE_SELECTED: + m_itemsPositioning.statusMessageSelectedYDiff = m_initialHeight - rcWindow.top; + break; + case IDC_STATUS_MESSAGE_RENAMING: + m_itemsPositioning.statusMessageRenamingYDiff = m_initialHeight - rcWindow.top; break; case ID_RENAME: m_itemsPositioning.renameButtonXDiff = m_initialWidth - rcWindow.left; diff --git a/src/modules/powerrename/ui/PowerRenameUI.h b/src/modules/powerrename/ui/PowerRenameUI.h index 35b79e0923..c0ef499156 100644 --- a/src/modules/powerrename/ui/PowerRenameUI.h +++ b/src/modules/powerrename/ui/PowerRenameUI.h @@ -83,7 +83,8 @@ private: int searchReplaceWidthDiff; int listPreviewWidthDiff; int listPreviewHeightDiff; - int statusMessageYDiff; + int statusMessageSelectedYDiff; + int statusMessageRenamingYDiff; int renameButtonXDiff; int renameButtonYDiff; int helpButtonXDiff; diff --git a/src/modules/powerrename/ui/Resources.resx b/src/modules/powerrename/ui/Resources.resx index c278b9c056..4da3576bbd 100644 --- a/src/modules/powerrename/ui/Resources.resx +++ b/src/modules/powerrename/ui/Resources.resx @@ -133,8 +133,11 @@ Please select from the options above to show items. Item Name and Extension - - Items Selected: %u | Renaming: %u + + Items Selected: %u + + + Items Renaming: %u Use Regular Expressions @@ -188,7 +191,10 @@ Please select from the options above to show items. Replace with: - Items Selected: 0 | Renaming: 0 + Items Selected: 0 + + + Items Renaming: 0 Options diff --git a/src/modules/powerrename/ui/resource.base.h b/src/modules/powerrename/ui/resource.base.h index 34b94ea1d9..a79a44208c 100644 --- a/src/modules/powerrename/ui/resource.base.h +++ b/src/modules/powerrename/ui/resource.base.h @@ -10,24 +10,25 @@ #define IDC_EDIT_REPLACEWITH 3003 #define IDC_LIST_PREVIEW 3004 #define IDC_CHECK_USEREGEX 3005 -#define IDC_STATUS_MESSAGE 3006 -#define IDC_CHECK_EXCLUDESUBFOLDERS 3007 -#define IDC_CHECK_ENUMITEMS 3008 -#define IDC_CHECK_EXCLUDEFILES 3009 -#define IDC_CHECK_CASESENSITIVE 3010 -#define IDC_CHECK_MATCHALLOCCURENCES 3011 -#define IDC_CHECK_EXCLUDEFOLDERS 3012 -#define IDC_CHECK_NAMEONLY 3013 -#define IDC_CHECK_EXTENSIONONLY 3014 -#define IDC_PREVIEWGROUP 3015 -#define IDC_OPTIONSGROUP 3016 -#define IDC_SEARCHREPLACEGROUP 3017 -#define IDC_TRANSFORM_UPPERCASE 3018 -#define IDC_TRANSFORM_LOWERCASE 3019 -#define IDC_TRANSFORM_TITLECASE 3020 -#define IDC_SEARCH_FOR 3021 -#define IDC_REPLACE_WITH 3022 +#define IDC_STATUS_MESSAGE_SELECTED 3006 +#define IDC_STATUS_MESSAGE_RENAMING 3007 +#define IDC_CHECK_EXCLUDESUBFOLDERS 3008 +#define IDC_CHECK_ENUMITEMS 3009 +#define IDC_CHECK_EXCLUDEFILES 3010 +#define IDC_CHECK_CASESENSITIVE 3011 +#define IDC_CHECK_MATCHALLOCCURENCES 3012 +#define IDC_CHECK_EXCLUDEFOLDERS 3013 +#define IDC_CHECK_NAMEONLY 3014 +#define IDC_CHECK_EXTENSIONONLY 3015 +#define IDC_PREVIEWGROUP 3016 +#define IDC_OPTIONSGROUP 3017 +#define IDC_SEARCHREPLACEGROUP 3018 +#define IDC_TRANSFORM_UPPERCASE 3019 +#define IDC_TRANSFORM_LOWERCASE 3020 +#define IDC_TRANSFORM_TITLECASE 3021 +#define IDC_SEARCH_FOR 3022 +#define IDC_REPLACE_WITH 3023 #define IDC_STATIC -1 -#define IDR_MAINFRAME 3023 -#define IDD_MAIN 3024 +#define IDR_MAINFRAME 3024 +#define IDD_MAIN 3025 #define IDI_RENAME 2001 diff --git a/src/modules/previewpane/MarkdownPreviewHandler/HTMLParsingExtension.cs b/src/modules/previewpane/MarkdownPreviewHandler/HTMLParsingExtension.cs index e703e586ba..b36467d4a1 100644 --- a/src/modules/previewpane/MarkdownPreviewHandler/HTMLParsingExtension.cs +++ b/src/modules/previewpane/MarkdownPreviewHandler/HTMLParsingExtension.cs @@ -2,8 +2,6 @@ // The Microsoft Corporation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; -using System.IO; using Markdig; using Markdig.Extensions.Figures; using Markdig.Extensions.Tables; diff --git a/src/modules/previewpane/MarkdownPreviewHandler/MarkdownPreviewHandler.csproj b/src/modules/previewpane/MarkdownPreviewHandler/MarkdownPreviewHandler.csproj index d120d518d0..9e2d5c4698 100644 --- a/src/modules/previewpane/MarkdownPreviewHandler/MarkdownPreviewHandler.csproj +++ b/src/modules/previewpane/MarkdownPreviewHandler/MarkdownPreviewHandler.csproj @@ -137,6 +137,9 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all + + 12.2.5 + diff --git a/src/modules/previewpane/MarkdownPreviewHandler/MarkdownPreviewHandlerControl.cs b/src/modules/previewpane/MarkdownPreviewHandler/MarkdownPreviewHandlerControl.cs index 5957756f4b..fe6b6f3310 100644 --- a/src/modules/previewpane/MarkdownPreviewHandler/MarkdownPreviewHandlerControl.cs +++ b/src/modules/previewpane/MarkdownPreviewHandler/MarkdownPreviewHandlerControl.cs @@ -4,7 +4,7 @@ using System; using System.Drawing; -using System.IO; +using System.IO.Abstractions; using System.Text.RegularExpressions; using System.Windows.Forms; using Common; @@ -21,6 +21,10 @@ namespace Microsoft.PowerToys.PreviewHandler.Markdown /// public class MarkdownPreviewHandlerControl : FormHandlerControl { + private static readonly IFileSystem FileSystem = new FileSystem(); + private static readonly IPath Path = FileSystem.Path; + private static readonly IFile File = FileSystem.File; + /// /// Extension to modify markdown AST. /// diff --git a/src/modules/previewpane/SvgPreviewHandler/Utilities/SvgPreviewHandlerHelper.cs b/src/modules/previewpane/SvgPreviewHandler/Utilities/SvgPreviewHandlerHelper.cs index 4ac672ebb7..c5af5df681 100644 --- a/src/modules/previewpane/SvgPreviewHandler/Utilities/SvgPreviewHandlerHelper.cs +++ b/src/modules/previewpane/SvgPreviewHandler/Utilities/SvgPreviewHandlerHelper.cs @@ -47,7 +47,10 @@ namespace Microsoft.PowerToys.PreviewHandler.Svg.Utilities var elements = doc.Descendants().ToList(); foreach (XElement element in elements) { - var elementName = element?.Name?.LocalName?.ToLower(CultureInfo.CurrentCulture); + // Using Invariant since we are doing an exact match for HTML tags and we want it to behave the same in every culture +#pragma warning disable CA1308 // Normalize strings to uppercase + var elementName = element?.Name?.LocalName?.ToLowerInvariant(); +#pragma warning restore CA1308 // Normalize strings to uppercase if (elementName != null && blockedElementsName.ContainsKey(elementName)) { foundBlockedElement = true; diff --git a/src/modules/previewpane/SvgThumbnailProvider/SvgThumbnailProvider.cs b/src/modules/previewpane/SvgThumbnailProvider/SvgThumbnailProvider.cs index 7f7c29f197..af09d1369d 100644 --- a/src/modules/previewpane/SvgThumbnailProvider/SvgThumbnailProvider.cs +++ b/src/modules/previewpane/SvgThumbnailProvider/SvgThumbnailProvider.cs @@ -166,7 +166,9 @@ namespace Microsoft.PowerToys.ThumbnailHandler.Svg {0} "; - return string.Format(CultureInfo.CurrentCulture, html, svg); + + // Using InvariantCulture since this should be displayed as it is + return string.Format(CultureInfo.InvariantCulture, html, svg); } /// diff --git a/src/modules/previewpane/common/PreviewHandlerCommon.csproj b/src/modules/previewpane/common/PreviewHandlerCommon.csproj index eae65aae56..b13fa2c908 100644 --- a/src/modules/previewpane/common/PreviewHandlerCommon.csproj +++ b/src/modules/previewpane/common/PreviewHandlerCommon.csproj @@ -148,6 +148,9 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all + + 12.2.5 + diff --git a/src/modules/previewpane/common/Utilities/ReadonlyStream.cs b/src/modules/previewpane/common/Utilities/ReadonlyStream.cs index a9ae949181..eb8d4a897a 100644 --- a/src/modules/previewpane/common/Utilities/ReadonlyStream.cs +++ b/src/modules/previewpane/common/Utilities/ReadonlyStream.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System; -using System.Diagnostics; using System.IO; using System.Runtime.InteropServices; using System.Runtime.InteropServices.ComTypes; diff --git a/src/modules/previewpane/common/controls/WebBrowserExt.cs b/src/modules/previewpane/common/controls/WebBrowserExt.cs index 5dcd44772a..05a3a3bff4 100644 --- a/src/modules/previewpane/common/controls/WebBrowserExt.cs +++ b/src/modules/previewpane/common/controls/WebBrowserExt.cs @@ -54,6 +54,7 @@ namespace PreviewHandlerCommon if (name != null && name.Equals(DISPIDAMBIENTDLCONTROL, StringComparison.CurrentCulture)) { + // Using InvariantCulture since this is used for web browser configurations result = Convert.ToInt32( WebBrowserDownloadControlFlags.DLIMAGES | WebBrowserDownloadControlFlags.PRAGMA_NO_CACHE | @@ -66,7 +67,7 @@ namespace PreviewHandlerCommon WebBrowserDownloadControlFlags.NO_DLACTIVEXCTLS | WebBrowserDownloadControlFlags.NO_RUNACTIVEXCTLS | WebBrowserDownloadControlFlags.NO_BEHAVIORS | - WebBrowserDownloadControlFlags.SILENT, CultureInfo.CurrentCulture); + WebBrowserDownloadControlFlags.SILENT, CultureInfo.InvariantCulture); } else { diff --git a/src/modules/previewpane/common/examplehandler/CustomControlTest.cs b/src/modules/previewpane/common/examplehandler/CustomControlTest.cs index 52fc860e54..1d7af54522 100644 --- a/src/modules/previewpane/common/examplehandler/CustomControlTest.cs +++ b/src/modules/previewpane/common/examplehandler/CustomControlTest.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System; -using System.IO; using System.Windows.Forms; namespace Common diff --git a/src/runner/LocProject.json b/src/runner/LocProject.json index 640d8f23ce..a7978f0a33 100644 --- a/src/runner/LocProject.json +++ b/src/runner/LocProject.json @@ -4,9 +4,9 @@ "LanguageSet": "Azure_Languages", "LocItems": [ { - "SourceFile": "src\\action_runner\\Resources.resx", + "SourceFile": "src\\runner\\Resources.resx", "CopyOption": "LangIDOnName", - "OutputPath": "src\\action_runner" + "OutputPath": "src\\runner" } ] } diff --git a/src/runner/Resources.resx b/src/runner/Resources.resx index 50f74f777e..836c1340d3 100644 --- a/src/runner/Resources.resx +++ b/src/runner/Resources.resx @@ -73,5 +73,85 @@ PowerToys was successfully updated! - + + An older version of PowerToys is already running. + + + Couldn't download PowerToys update! Please report the issue on Github. + + + An older MSIX version of PowerToys was uninstalled. + + + PowerToys was updated successfully! + + + This setting has been disabled by your administrator. + + + This setting has been disabled manually via <a href="https://ms_settings_startupapps" target="_blank">Startup Settings</a>. + + + An update to PowerToys is available. + + + PowerToys download started. + + + An update to PowerToys is ready to install. + + + Error: couldn't download PowerToys installer. Visit our GitHub page to update. + + + Update now + + + At next launch + + + Error: please uninstall the previous version of PowerToys manually. + + + An update to PowerToys is available. Visit our GitHub page to update. + + + PowerToys is up to date. + + + Visit + + + More info... + + + Abort + + + Click Snooze to be reminded in: + + + 1 day + + + 5 days + + + Downloading... + + + Download complete + + + PowerToys Update + + + We've detected a previous installation of PowerToys. Would you like to remove it? + + + PowerToys: uninstall previous version? + + + Snooze + \ No newline at end of file diff --git a/src/runner/general_settings.cpp b/src/runner/general_settings.cpp index a1f4ce357a..5c7e950da5 100644 --- a/src/runner/general_settings.cpp +++ b/src/runner/general_settings.cpp @@ -1,6 +1,7 @@ #include "pch.h" #include "general_settings.h" #include "auto_start_helper.h" +#include "Generated files/resource.h" #include #include @@ -15,12 +16,7 @@ static std::wstring settings_theme = L"system"; static bool run_as_elevated = false; static bool download_updates_automatically = true; -// TODO: add resource.rc for settings project and localize -namespace localized_strings -{ - const std::wstring_view STARTUP_DISABLED_BY_POLICY = L"This setting has been disabled by your administrator."; - const std::wstring_view STARTUP_DISABLED_BY_USER = LR"(This setting has been disabled manually via Startup Settings.)"; -} +extern "C" IMAGE_DOS_HEADER __ImageBase; json::JsonObject GeneralSettings::to_json() { @@ -81,7 +77,6 @@ GeneralSettings get_general_settings() if (winstore::running_as_packaged()) { - using namespace localized_strings; const auto task_state = winstore::get_startup_task_status_async().get(); switch (task_state) { @@ -92,11 +87,11 @@ GeneralSettings get_general_settings() settings.isStartupEnabled = true; break; case winstore::StartupTaskState::DisabledByPolicy: - settings.startupDisabledReason = STARTUP_DISABLED_BY_POLICY; + settings.startupDisabledReason = GET_RESOURCE_STRING(IDS_STARTUP_DISABLED_BY_POLICY); settings.isStartupEnabled = false; break; case winstore::StartupTaskState::DisabledByUser: - settings.startupDisabledReason = STARTUP_DISABLED_BY_USER; + settings.startupDisabledReason = GET_RESOURCE_STRING(IDS_STARTUP_DISABLED_BY_USER); settings.isStartupEnabled = false; break; } diff --git a/src/runner/loc/cs/src/action_runner/Resources.resx.lcl b/src/runner/loc/cs/src/action_runner/Resources.resx.lcl index 8beb29a7c1..89e892c2e6 100644 --- a/src/runner/loc/cs/src/action_runner/Resources.resx.lcl +++ b/src/runner/loc/cs/src/action_runner/Resources.resx.lcl @@ -13,12 +13,18 @@ + + + + + + diff --git a/src/runner/loc/de/src/action_runner/Resources.resx.lcl b/src/runner/loc/de/src/action_runner/Resources.resx.lcl index d99f085585..5826030b5c 100644 --- a/src/runner/loc/de/src/action_runner/Resources.resx.lcl +++ b/src/runner/loc/de/src/action_runner/Resources.resx.lcl @@ -13,12 +13,18 @@ + + + + + + diff --git a/src/runner/loc/es/src/action_runner/Resources.resx.lcl b/src/runner/loc/es/src/action_runner/Resources.resx.lcl index d78d024efc..2f978f7757 100644 --- a/src/runner/loc/es/src/action_runner/Resources.resx.lcl +++ b/src/runner/loc/es/src/action_runner/Resources.resx.lcl @@ -13,12 +13,18 @@ + + + + + + diff --git a/src/runner/loc/fr/src/action_runner/Resources.resx.lcl b/src/runner/loc/fr/src/action_runner/Resources.resx.lcl index 639270293d..e2d38405a8 100644 --- a/src/runner/loc/fr/src/action_runner/Resources.resx.lcl +++ b/src/runner/loc/fr/src/action_runner/Resources.resx.lcl @@ -13,12 +13,18 @@ + + + + + + diff --git a/src/runner/loc/hu/src/action_runner/Resources.resx.lcl b/src/runner/loc/hu/src/action_runner/Resources.resx.lcl index 0c36c36a11..d87852e4fd 100644 --- a/src/runner/loc/hu/src/action_runner/Resources.resx.lcl +++ b/src/runner/loc/hu/src/action_runner/Resources.resx.lcl @@ -13,12 +13,18 @@ + + + + + + diff --git a/src/runner/loc/ja/src/action_runner/Resources.resx.lcl b/src/runner/loc/ja/src/action_runner/Resources.resx.lcl index b60fa45e9d..bee976fffd 100644 --- a/src/runner/loc/ja/src/action_runner/Resources.resx.lcl +++ b/src/runner/loc/ja/src/action_runner/Resources.resx.lcl @@ -13,12 +13,18 @@ + + + + + + diff --git a/src/runner/loc/nl/src/action_runner/Resources.resx.lcl b/src/runner/loc/nl/src/action_runner/Resources.resx.lcl index aeef6a2496..f6532ba6d9 100644 --- a/src/runner/loc/nl/src/action_runner/Resources.resx.lcl +++ b/src/runner/loc/nl/src/action_runner/Resources.resx.lcl @@ -13,12 +13,18 @@ + + + + + + diff --git a/src/runner/loc/pt-BR/src/action_runner/Resources.resx.lcl b/src/runner/loc/pt-BR/src/action_runner/Resources.resx.lcl index 79e1b8e479..4c5dbe8c3c 100644 --- a/src/runner/loc/pt-BR/src/action_runner/Resources.resx.lcl +++ b/src/runner/loc/pt-BR/src/action_runner/Resources.resx.lcl @@ -13,12 +13,18 @@ + + + + + + diff --git a/src/runner/loc/ru/src/action_runner/Resources.resx.lcl b/src/runner/loc/ru/src/action_runner/Resources.resx.lcl index 807b9d35ed..4d9d4a3b2b 100644 --- a/src/runner/loc/ru/src/action_runner/Resources.resx.lcl +++ b/src/runner/loc/ru/src/action_runner/Resources.resx.lcl @@ -13,12 +13,18 @@ + + + + + + diff --git a/src/runner/loc/sv/src/action_runner/Resources.resx.lcl b/src/runner/loc/sv/src/action_runner/Resources.resx.lcl index ed0367d71f..c7408b5485 100644 --- a/src/runner/loc/sv/src/action_runner/Resources.resx.lcl +++ b/src/runner/loc/sv/src/action_runner/Resources.resx.lcl @@ -13,12 +13,18 @@ + + + + + + diff --git a/src/runner/loc/tr/src/action_runner/Resources.resx.lcl b/src/runner/loc/tr/src/action_runner/Resources.resx.lcl index 12956b6344..6f0ecc85e8 100644 --- a/src/runner/loc/tr/src/action_runner/Resources.resx.lcl +++ b/src/runner/loc/tr/src/action_runner/Resources.resx.lcl @@ -13,12 +13,18 @@ + + + + + + diff --git a/src/runner/loc/zh-Hans/src/action_runner/Resources.resx.lcl b/src/runner/loc/zh-Hans/src/action_runner/Resources.resx.lcl index a093755685..dcae1a05a7 100644 --- a/src/runner/loc/zh-Hans/src/action_runner/Resources.resx.lcl +++ b/src/runner/loc/zh-Hans/src/action_runner/Resources.resx.lcl @@ -13,12 +13,18 @@ + + + + + + diff --git a/src/runner/main.cpp b/src/runner/main.cpp index ec7a56ad0c..d68a1fec1d 100644 --- a/src/runner/main.cpp +++ b/src/runner/main.cpp @@ -35,20 +35,12 @@ #endif extern "C" IMAGE_DOS_HEADER __ImageBase; - -namespace localized_strings -{ - const wchar_t MSI_VERSION_IS_ALREADY_RUNNING[] = L"An older version of PowerToys is already running."; - const wchar_t DOWNLOAD_UPDATE_ERROR[] = L"Couldn't download PowerToys update! Please report the issue on Github."; - const wchar_t OLDER_MSIX_UNINSTALLED[] = L"An older MSIX version of PowerToys was uninstalled."; - const wchar_t PT_UPDATE_MESSAGE_BOX_TEXT[] = L"PowerToys was updated successfully!"; - const wchar_t POWER_TOYS[] = L"PowerToys"; - const wchar_t POWER_TOYS_MODULE_LOAD_FAIL[] = L"Failed to load "; // Module name will be appended on this message and it is not localized. -} +extern updating::notifications::strings Strings; namespace { const wchar_t PT_URI_PROTOCOL_SCHEME[] = L"powertoys://"; + const wchar_t POWER_TOYS_MODULE_LOAD_FAIL[] = L"Failed to load "; // Module name will be appended on this message and it is not localized. } void chdir_current_executable() @@ -59,7 +51,7 @@ void chdir_current_executable() PathRemoveFileSpec(executable_path); if (!SetCurrentDirectory(executable_path)) { - show_last_error_message(L"Change Directory to Executable Path", GetLastError()); + show_last_error_message(L"Change Directory to Executable Path", GetLastError(), L"PowerToys - runner"); } } @@ -110,7 +102,7 @@ int runner(bool isProcessElevated) std::thread{ [] { if (updating::uninstall_previous_msix_version_async().get()) { - notifications::show_toast(localized_strings::OLDER_MSIX_UNINSTALLED, L"PowerToys"); + notifications::show_toast(GET_RESOURCE_STRING(IDS_OLDER_MSIX_UNINSTALLED).c_str(), L"PowerToys"); } } }.detach(); } @@ -140,11 +132,12 @@ int runner(bool isProcessElevated) } catch (...) { - std::wstring errorMessage = std::wstring(localized_strings::POWER_TOYS_MODULE_LOAD_FAIL) + moduleSubdir.data(); - MessageBox(NULL, - errorMessage.c_str(), - localized_strings::POWER_TOYS, - MB_OK | MB_ICONERROR); + std::wstring errorMessage = POWER_TOYS_MODULE_LOAD_FAIL; + errorMessage += moduleSubdir; + MessageBoxW(NULL, + errorMessage.c_str(), + L"PowerToys", + MB_OK | MB_ICONERROR); } } // Start initial powertoys @@ -243,7 +236,7 @@ toast_notification_handler_result toast_notification_handler(const std::wstring_ { try { - std::wstring installer_filename = updating::download_update().get(); + std::wstring installer_filename = updating::download_update(Strings).get(); std::wstring args{ UPDATE_NOW_LAUNCH_STAGE1_CMDARG }; args += L' '; @@ -255,7 +248,7 @@ toast_notification_handler_result toast_notification_handler(const std::wstring_ catch (...) { MessageBoxW(nullptr, - localized_strings::DOWNLOAD_UPDATE_ERROR, + GET_RESOURCE_STRING(IDS_DOWNLOAD_UPDATE_ERROR).c_str(), L"PowerToys", MB_ICONWARNING | MB_OK); @@ -314,7 +307,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine case SpecialMode::ReportSuccessfulUpdate: { notifications::remove_toasts(notifications::UPDATING_PROCESS_TOAST_TAG); - notifications::show_toast(localized_strings::PT_UPDATE_MESSAGE_BOX_TEXT, + notifications::show_toast(GET_RESOURCE_STRING(IDS_PT_UPDATE_MESSAGE_BOX_TEXT), L"PowerToys", notifications::toast_params{ notifications::UPDATING_PROCESS_TOAST_TAG }); break; diff --git a/src/runner/settings_window.cpp b/src/runner/settings_window.cpp index aae24cac88..439e2cdf08 100644 --- a/src/runner/settings_window.cpp +++ b/src/runner/settings_window.cpp @@ -390,7 +390,7 @@ void run_settings_window() WaitForSingleObject(process_info.hProcess, INFINITE); if (WaitForSingleObject(process_info.hProcess, INFINITE) != WAIT_OBJECT_0) { - show_last_error_message(L"Couldn't wait on the Settings Window to close.", GetLastError()); + show_last_error_message(L"Couldn't wait on the Settings Window to close.", GetLastError(), L"PowerToys - runner"); } LExit: diff --git a/src/runner/update_utils.cpp b/src/runner/update_utils.cpp index c66d16dbeb..5a2f30eb8b 100644 --- a/src/runner/update_utils.cpp +++ b/src/runner/update_utils.cpp @@ -1,5 +1,8 @@ #include "pch.h" +#include +#include "Generated Files/resource.h" + #include "action_runner_utils.h" #include "update_state.h" #include "update_utils.h" @@ -8,6 +11,10 @@ #include #include +extern "C" IMAGE_DOS_HEADER __ImageBase; + +auto Strings = updating::notifications::strings::create(); + bool start_msi_uninstallation_sequence() { const auto package_path = updating::get_msi_package_path(); @@ -18,7 +25,7 @@ bool start_msi_uninstallation_sequence() return true; } - if (!updating::offer_msi_uninstallation()) + if (!updating::offer_msi_uninstallation(Strings)) { // User declined to uninstall or opted for "Don't show again" return false; @@ -54,7 +61,7 @@ void github_update_worker() const bool download_updates_automatically = get_general_settings().downloadUpdatesAutomatically; try { - updating::try_autoupdate(download_updates_automatically).get(); + updating::try_autoupdate(download_updates_automatically, Strings).get(); } catch (...) { @@ -70,7 +77,7 @@ std::wstring check_for_updates() { try { - return updating::check_new_version_available().get(); + return updating::check_new_version_available(Strings).get(); } catch (...) { diff --git a/src/tests/win-app-driver/FancyZonesTests/EditorCustomLayoutsTests.cs b/src/tests/win-app-driver/FancyZonesTests/EditorCustomLayoutsTests.cs index 840ee77013..1f75ba18a9 100644 --- a/src/tests/win-app-driver/FancyZonesTests/EditorCustomLayoutsTests.cs +++ b/src/tests/win-app-driver/FancyZonesTests/EditorCustomLayoutsTests.cs @@ -1,4 +1,4 @@ -using System.IO; +using System.IO.Abstractions; using Microsoft.VisualStudio.TestTools.UnitTesting; using Newtonsoft.Json.Linq; using OpenQA.Selenium; @@ -11,6 +11,9 @@ namespace PowerToysTests [TestClass] public class FancyZonesEditorCustomLayoutsTests : FancyZonesEditor { + private static readonly IFileSystem FileSystem = new FileSystem(); + private static readonly IFile File = FileSystem.File; + private void SetLayoutName(string name) { AppiumWebElement textBox = creatorWindow.FindElementByClassName("TextBox"); diff --git a/src/tests/win-app-driver/FancyZonesTests/EditorOpeningTests.cs b/src/tests/win-app-driver/FancyZonesTests/EditorOpeningTests.cs index ded0f49361..f26a09af88 100644 --- a/src/tests/win-app-driver/FancyZonesTests/EditorOpeningTests.cs +++ b/src/tests/win-app-driver/FancyZonesTests/EditorOpeningTests.cs @@ -1,4 +1,4 @@ -using System.IO; +using System.IO.Abstractions; using Microsoft.VisualStudio.TestTools.UnitTesting; using OpenQA.Selenium.Appium; using OpenQA.Selenium.Appium.Windows; @@ -9,6 +9,9 @@ namespace PowerToysTests [TestClass] public class FancyZonesEditorOpeningTests : FancyZonesEditor { + private static readonly IFileSystem FileSystem = new FileSystem(); + private static readonly IFile File = FileSystem.File; + private static readonly IDirectory Directory = FileSystem.Directory; void RemoveSettingsFile() { File.Delete(_zoneSettingsPath); diff --git a/src/tests/win-app-driver/FancyZonesTests/EditorSettingsTests.cs b/src/tests/win-app-driver/FancyZonesTests/EditorSettingsTests.cs index 3df7f2a4f6..ca4c807469 100644 --- a/src/tests/win-app-driver/FancyZonesTests/EditorSettingsTests.cs +++ b/src/tests/win-app-driver/FancyZonesTests/EditorSettingsTests.cs @@ -1,5 +1,6 @@ using System; -using System.IO; +using System.IO.Abstractions; +//using System.IO; using Microsoft.VisualStudio.TestTools.UnitTesting; using Newtonsoft.Json.Linq; using OpenQA.Selenium; @@ -10,6 +11,9 @@ namespace PowerToysTests [TestClass] public class FancyZonesEditorSettingsTests : FancyZonesEditor { + private static readonly IFileSystem FileSystem = new FileSystem(); + private static readonly IFile File = FileSystem.File; + private const string editorZoneCount = "editor-zone-count"; private const string editorShowSpacing = "editor-show-spacing"; private const string editorSpacing = "editor-spacing"; diff --git a/src/tests/win-app-driver/FancyZonesTests/EditorTemplatesApplyTests.cs b/src/tests/win-app-driver/FancyZonesTests/EditorTemplatesApplyTests.cs index 238321cbaa..ace3aa3fc3 100644 --- a/src/tests/win-app-driver/FancyZonesTests/EditorTemplatesApplyTests.cs +++ b/src/tests/win-app-driver/FancyZonesTests/EditorTemplatesApplyTests.cs @@ -1,4 +1,4 @@ -using System.IO; +using System.IO.Abstractions; using Microsoft.VisualStudio.TestTools.UnitTesting; using Newtonsoft.Json.Linq; @@ -7,6 +7,9 @@ namespace PowerToysTests [TestClass] public class FancyZonesEditorTemplatesApplyTests : FancyZonesEditor { + private static readonly IFileSystem FileSystem = new FileSystem(); + private static readonly IFile File = FileSystem.File; + private void ApplyLayout(string tabName) { editorWindow.FindElementByName(tabName).Click(); diff --git a/src/tests/win-app-driver/FancyZonesTests/EditorTemplatesEditTests.cs b/src/tests/win-app-driver/FancyZonesTests/EditorTemplatesEditTests.cs index 8d078a538a..6d1b922bb5 100644 --- a/src/tests/win-app-driver/FancyZonesTests/EditorTemplatesEditTests.cs +++ b/src/tests/win-app-driver/FancyZonesTests/EditorTemplatesEditTests.cs @@ -1,4 +1,4 @@ -using System.IO; +using System.IO.Abstractions; using Microsoft.VisualStudio.TestTools.UnitTesting; using Newtonsoft.Json.Linq; using OpenQA.Selenium.Appium; @@ -9,6 +9,8 @@ namespace PowerToysTests [TestClass] public class FancyZonesEditorTemplatesEditTests : FancyZonesEditor { + private static readonly IFileSystem FileSystem = new FileSystem(); + private static readonly IFile File = FileSystem.File; private void ChangeLayout() { new Actions(session).MoveToElement(creatorWindow.FindElementByAccessibilityId("PART_TitleBar")).MoveByOffset(0, -50).Click().Perform(); diff --git a/src/tests/win-app-driver/FancyZonesTests/FancyZonesSettingsTests.cs b/src/tests/win-app-driver/FancyZonesTests/FancyZonesSettingsTests.cs index 78e3d17252..2c8ea49139 100644 --- a/src/tests/win-app-driver/FancyZonesTests/FancyZonesSettingsTests.cs +++ b/src/tests/win-app-driver/FancyZonesTests/FancyZonesSettingsTests.cs @@ -1,7 +1,7 @@ using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; -using System.IO; +using System.IO.Abstractions; using System.Linq; using System.Windows.Forms; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -16,6 +16,10 @@ namespace PowerToysTests [TestClass] public class FancyZonesSettingsTests : PowerToysSession { + private static readonly IFileSystem FileSystem = new FileSystem(); + private static readonly IFile File = FileSystem.File; + + private JObject _initialSettingsJson; private static WindowsElement _saveButton; diff --git a/src/tests/win-app-driver/PowerToysSession.cs b/src/tests/win-app-driver/PowerToysSession.cs index 172534858b..479507e07f 100644 --- a/src/tests/win-app-driver/PowerToysSession.cs +++ b/src/tests/win-app-driver/PowerToysSession.cs @@ -1,6 +1,5 @@ using System; -using System.Diagnostics; -using System.IO; +using System.IO.Abstractions; using System.Threading; using Microsoft.VisualStudio.TestTools.UnitTesting; using Newtonsoft.Json.Linq; @@ -13,6 +12,11 @@ namespace PowerToysTests { public class PowerToysSession { + private static readonly IFileSystem FileSystem = new FileSystem(); + private static readonly IPath Path = FileSystem.Path; + private static readonly IFile File = FileSystem.File; + private static readonly IDirectory Directory = FileSystem.Directory; + protected const string WindowsApplicationDriverUrl = "http://127.0.0.1:4723"; protected const string AppPath = "C:\\Program Files\\PowerToys\\PowerToys.exe"; diff --git a/src/tests/win-app-driver/packages.config b/src/tests/win-app-driver/packages.config index 0b2d273254..c976291d81 100644 --- a/src/tests/win-app-driver/packages.config +++ b/src/tests/win-app-driver/packages.config @@ -8,4 +8,5 @@ + \ No newline at end of file diff --git a/src/tests/win-app-driver/win-app-driver.csproj b/src/tests/win-app-driver/win-app-driver.csproj index 3a12583122..5907d4bd17 100644 --- a/src/tests/win-app-driver/win-app-driver.csproj +++ b/src/tests/win-app-driver/win-app-driver.csproj @@ -109,6 +109,9 @@ C:\Windows\Microsoft.NET\assembly\GAC_MSIL\System.Core\v4.0_4.0.0.0__b77a5c561934e089\System.Core.dll + + ..\..\..\packages\System.IO.Abstractions.12.2.5\lib\net461\System.IO.Abstractions.dll + ..\..\..\packages\Selenium.WebDriver.3.141.0\lib\net45\WebDriver.dll diff --git a/tools/build/convert-resx-to-rc.ps1 b/tools/build/convert-resx-to-rc.ps1 index 6a6fab526b..748e6c1731 100644 --- a/tools/build/convert-resx-to-rc.ps1 +++ b/tools/build/convert-resx-to-rc.ps1 @@ -177,7 +177,7 @@ try { Set-Content -Path $generatedFilesFolder\$generatedHeaderFileName -Value $headerFileContent } else { - echo "Skipping write to generated header file" + # echo "Skipping write to generated header file" } } catch { @@ -191,7 +191,7 @@ try { Set-Content -Path $generatedFilesFolder\$generatedRCFileName -Value $rcFileContent -Encoding unicode } else { - echo "Skipping write to generated rc file" + # echo "Skipping write to generated rc file" } } catch {