From 397627123e18583ef9b6de2f786a817383b14adc Mon Sep 17 00:00:00 2001 From: Seraphima Zykova Date: Tue, 16 Mar 2021 20:06:54 +0300 Subject: [PATCH] [FZ Editor] Layout hotkeys for quick swap UI: Parsing/serializing quick keys, telemetry (#10243) --- .github/actions/spell-check/expect.txt | 1 + src/modules/fancyzones/lib/FancyZonesData.cpp | 3 +- src/modules/fancyzones/lib/FancyZonesData.h | 8 ++ src/modules/fancyzones/lib/JsonHelpers.cpp | 82 ++++++++++++-- src/modules/fancyzones/lib/JsonHelpers.h | 15 ++- src/modules/fancyzones/lib/trace.cpp | 5 +- .../tests/UnitTests/JsonHelpers.Tests.cpp | 103 ++++++++++++------ 7 files changed, 174 insertions(+), 43 deletions(-) diff --git a/.github/actions/spell-check/expect.txt b/.github/actions/spell-check/expect.txt index 436038accde7..e87682e2a391 100644 --- a/.github/actions/spell-check/expect.txt +++ b/.github/actions/spell-check/expect.txt @@ -2095,6 +2095,7 @@ Timeline timeunion timeutil titlecase +TLayout tlb tlbimp tmp diff --git a/src/modules/fancyzones/lib/FancyZonesData.cpp b/src/modules/fancyzones/lib/FancyZonesData.cpp index 487b8b862fed..0ea783a28d06 100644 --- a/src/modules/fancyzones/lib/FancyZonesData.cpp +++ b/src/modules/fancyzones/lib/FancyZonesData.cpp @@ -536,6 +536,7 @@ void FancyZonesData::LoadFancyZonesData() appZoneHistoryMap = JSONHelpers::ParseAppZoneHistory(fancyZonesDataJSON); deviceInfoMap = JSONHelpers::ParseDeviceInfos(fancyZonesDataJSON); customZoneSetsMap = JSONHelpers::ParseCustomZoneSets(fancyZonesDataJSON); + quickKeysMap = JSONHelpers::ParseQuickKeys(fancyZonesDataJSON); } } @@ -549,7 +550,7 @@ void FancyZonesData::SaveZoneSettings() const { _TRACER_; std::scoped_lock lock{ dataLock }; - JSONHelpers::SaveZoneSettings(zonesSettingsFileName, deviceInfoMap, customZoneSetsMap); + JSONHelpers::SaveZoneSettings(zonesSettingsFileName, deviceInfoMap, customZoneSetsMap, quickKeysMap); } void FancyZonesData::SaveAppZoneHistory() const diff --git a/src/modules/fancyzones/lib/FancyZonesData.h b/src/modules/fancyzones/lib/FancyZonesData.h index aea46093a912..34dc72b6fd8e 100644 --- a/src/modules/fancyzones/lib/FancyZonesData.h +++ b/src/modules/fancyzones/lib/FancyZonesData.h @@ -48,6 +48,12 @@ class FancyZonesData const std::unordered_map>& GetAppZoneHistoryMap() const; + inline const JSONHelpers::TLayoutQuickKeysMap& GetLayoutQuickKeys() const + { + std::scoped_lock lock{ dataLock }; + return quickKeysMap; + } + inline const std::wstring& GetZonesSettingsFileName() const { return zonesSettingsFileName; @@ -121,6 +127,8 @@ class FancyZonesData JSONHelpers::TDeviceInfoMap deviceInfoMap{}; // Maps custom zoneset UUID to it's data JSONHelpers::TCustomZoneSetsMap customZoneSetsMap{}; + // Maps zoneset UUID with quick access keys + JSONHelpers::TLayoutQuickKeysMap quickKeysMap{}; std::wstring zonesSettingsFileName; std::wstring appZoneHistoryFileName; diff --git a/src/modules/fancyzones/lib/JsonHelpers.cpp b/src/modules/fancyzones/lib/JsonHelpers.cpp index 5cc2636233dc..d6b8570e3337 100644 --- a/src/modules/fancyzones/lib/JsonHelpers.cpp +++ b/src/modules/fancyzones/lib/JsonHelpers.cpp @@ -30,12 +30,14 @@ namespace NonLocalizable const wchar_t EditorSpacingStr[] = L"editor-spacing"; const wchar_t EditorZoneCountStr[] = L"editor-zone-count"; const wchar_t EditorSensitivityRadiusStr[] = L"editor-sensitivity-radius"; - const wchar_t FastAccessLayoutKeys[] = L"fast-access-layout-keys"; const wchar_t GridStr[] = L"grid"; const wchar_t HeightStr[] = L"height"; const wchar_t HistoryStr[] = L"history"; const wchar_t InfoStr[] = L"info"; const wchar_t NameStr[] = L"name"; + const wchar_t QuickAccessKey[] = L"key"; + const wchar_t QuickAccessUuid[] = L"uuid"; + const wchar_t QuickLayoutKeys[] = L"quick-layout-keys"; const wchar_t RefHeightStr[] = L"ref-height"; const wchar_t RefWidthStr[] = L"ref-width"; const wchar_t RowsPercentageStr[] = L"rows-percentage"; @@ -472,6 +474,38 @@ namespace JSONHelpers } } + json::JsonObject LayoutQuickKeyJSON::ToJson(const LayoutQuickKeyJSON& layoutQuickKey) + { + json::JsonObject result{}; + + result.SetNamedValue(NonLocalizable::QuickAccessUuid, json::value(layoutQuickKey.layoutUuid)); + result.SetNamedValue(NonLocalizable::QuickAccessKey, json::value(layoutQuickKey.key)); + + return result; + } + + std::optional LayoutQuickKeyJSON::FromJson(const json::JsonObject& layoutQuickKey) + { + try + { + LayoutQuickKeyJSON result; + + result.layoutUuid = layoutQuickKey.GetNamedString(NonLocalizable::QuickAccessUuid); + if (!FancyZonesUtils::IsValidGuid(result.layoutUuid)) + { + return std::nullopt; + } + + result.key = static_cast(layoutQuickKey.GetNamedNumber(NonLocalizable::QuickAccessKey)); + + return result; + } + catch (const winrt::hresult_error&) + { + return std::nullopt; + } + } + json::JsonObject MonitorInfo::ToJson(const MonitorInfo& monitor) { json::JsonObject result{}; @@ -528,13 +562,12 @@ namespace JSONHelpers } } - void SaveZoneSettings(const std::wstring& zonesSettingsFileName, const TDeviceInfoMap& deviceInfoMap, const TCustomZoneSetsMap& customZoneSetsMap) + void SaveZoneSettings(const std::wstring& zonesSettingsFileName, const TDeviceInfoMap& deviceInfoMap, const TCustomZoneSetsMap& customZoneSetsMap, const TLayoutQuickKeysMap& quickKeysMap) { auto before = json::from_file(zonesSettingsFileName); json::JsonObject root{}; json::JsonArray templates{}; - json::JsonArray fastAccessLayoutKeys{}; try { @@ -542,11 +575,6 @@ namespace JSONHelpers { templates = before->GetNamedArray(NonLocalizable::Templates); } - - if (before.has_value() && before->HasKey(NonLocalizable::FastAccessLayoutKeys)) - { - fastAccessLayoutKeys = before->GetNamedArray(NonLocalizable::FastAccessLayoutKeys); - } } catch (const winrt::hresult_error&) { @@ -556,7 +584,7 @@ namespace JSONHelpers root.SetNamedValue(NonLocalizable::DevicesStr, JSONHelpers::SerializeDeviceInfos(deviceInfoMap)); root.SetNamedValue(NonLocalizable::CustomZoneSetsStr, JSONHelpers::SerializeCustomZoneSets(customZoneSetsMap)); root.SetNamedValue(NonLocalizable::Templates, templates); - root.SetNamedValue(NonLocalizable::FastAccessLayoutKeys, fastAccessLayoutKeys); + root.SetNamedValue(NonLocalizable::QuickLayoutKeys, JSONHelpers::SerializeQuickKeys(quickKeysMap)); if (!before.has_value() || before.value().Stringify() != root.Stringify()) { @@ -683,4 +711,40 @@ namespace JSONHelpers return customZoneSetsJSON; } + + TLayoutQuickKeysMap ParseQuickKeys(const json::JsonObject& fancyZonesDataJSON) + { + try + { + TLayoutQuickKeysMap quickKeysMap{}; + auto quickKeys = fancyZonesDataJSON.GetNamedArray(NonLocalizable::QuickLayoutKeys); + + for (uint32_t i = 0; i < quickKeys.Size(); ++i) + { + if (auto quickKey = LayoutQuickKeyJSON::FromJson(quickKeys.GetObjectAt(i)); quickKey.has_value()) + { + quickKeysMap[quickKey->layoutUuid] = std::move(quickKey->key); + } + } + + return std::move(quickKeysMap); + } + catch (const winrt::hresult_error& e) + { + Logger::error(L"Parsing quick keys error: {}", e.message()); + return {}; + } + } + + json::JsonArray SerializeQuickKeys(const TLayoutQuickKeysMap& quickKeysMap) + { + json::JsonArray quickKeysJSON{}; + + for (const auto& [uuid, key] : quickKeysMap) + { + quickKeysJSON.Append(LayoutQuickKeyJSON::ToJson(LayoutQuickKeyJSON{ uuid, key })); + } + + return quickKeysJSON; + } } \ No newline at end of file diff --git a/src/modules/fancyzones/lib/JsonHelpers.h b/src/modules/fancyzones/lib/JsonHelpers.h index eb933721e87d..52d3bc327cca 100644 --- a/src/modules/fancyzones/lib/JsonHelpers.h +++ b/src/modules/fancyzones/lib/JsonHelpers.h @@ -55,9 +55,19 @@ namespace JSONHelpers static std::optional FromJson(const json::JsonObject& device); }; + struct LayoutQuickKeyJSON + { + std::wstring layoutUuid; + int key; + + static json::JsonObject ToJson(const LayoutQuickKeyJSON& device); + static std::optional FromJson(const json::JsonObject& device); + }; + using TAppZoneHistoryMap = std::unordered_map>; using TDeviceInfoMap = std::unordered_map; using TCustomZoneSetsMap = std::unordered_map; + using TLayoutQuickKeysMap = std::unordered_map; struct MonitorInfo { @@ -81,7 +91,7 @@ namespace JSONHelpers json::JsonObject GetPersistFancyZonesJSON(const std::wstring& zonesSettingsFileName, const std::wstring& appZoneHistoryFileName); - void SaveZoneSettings(const std::wstring& zonesSettingsFileName, const TDeviceInfoMap& deviceInfoMap, const TCustomZoneSetsMap& customZoneSetsMap); + void SaveZoneSettings(const std::wstring& zonesSettingsFileName, const TDeviceInfoMap& deviceInfoMap, const TCustomZoneSetsMap& customZoneSetsMap, const TLayoutQuickKeysMap& quickKeysMap); void SaveAppZoneHistory(const std::wstring& appZoneHistoryFileName, const TAppZoneHistoryMap& appZoneHistoryMap); TAppZoneHistoryMap ParseAppZoneHistory(const json::JsonObject& fancyZonesDataJSON); @@ -92,4 +102,7 @@ namespace JSONHelpers TCustomZoneSetsMap ParseCustomZoneSets(const json::JsonObject& fancyZonesDataJSON); json::JsonArray SerializeCustomZoneSets(const TCustomZoneSetsMap& customZoneSetsMap); + + TLayoutQuickKeysMap ParseQuickKeys(const json::JsonObject& fancyZonesDataJSON); + json::JsonArray SerializeQuickKeys(const TLayoutQuickKeysMap& quickKeysMap); } diff --git a/src/modules/fancyzones/lib/trace.cpp b/src/modules/fancyzones/lib/trace.cpp index 9961c2f8f4db..5213957005ca 100644 --- a/src/modules/fancyzones/lib/trace.cpp +++ b/src/modules/fancyzones/lib/trace.cpp @@ -25,6 +25,7 @@ #define MoveSizeActionKey "InMoveSize" #define AppsInHistoryCountKey "AppsInHistoryCount" #define CustomZoneSetCountKey "CustomZoneSetCount" +#define LayoutUsingQuickKeyCountKey "LayoutUsingQuickKeyCount" #define NumberOfZonesForEachCustomZoneSetKey "NumberOfZonesForEachCustomZoneSet" #define ActiveZoneSetsCountKey "ActiveZoneSetsCount" #define ActiveZoneSetsListKey "ActiveZoneSetsList" @@ -128,6 +129,7 @@ void Trace::FancyZones::DataChanged() noexcept int appsHistorySize = static_cast(data.GetAppZoneHistoryMap().size()); const auto& customZones = data.GetCustomZoneSetsMap(); const auto& devices = data.GetDeviceInfoMap(); + const auto& quickKeys = data.GetLayoutQuickKeys(); std::unique_ptr customZonesArray(new (std::nothrow) INT32[customZones.size()]); if (!customZonesArray) @@ -201,7 +203,8 @@ void Trace::FancyZones::DataChanged() noexcept TraceLoggingInt32(static_cast(customZones.size()), CustomZoneSetCountKey), TraceLoggingInt32Array(customZonesArray.get(), static_cast(customZones.size()), NumberOfZonesForEachCustomZoneSetKey), TraceLoggingInt32(static_cast(devices.size()), ActiveZoneSetsCountKey), - TraceLoggingWideString(activeZoneSetInfo.c_str(), ActiveZoneSetsListKey)); + TraceLoggingWideString(activeZoneSetInfo.c_str(), ActiveZoneSetsListKey), + TraceLoggingInt32(static_cast(quickKeys.size()), LayoutUsingQuickKeyCountKey)); } void Trace::FancyZones::EditorLaunched(int value) noexcept diff --git a/src/modules/fancyzones/tests/UnitTests/JsonHelpers.Tests.cpp b/src/modules/fancyzones/tests/UnitTests/JsonHelpers.Tests.cpp index edc08082258a..76aaadeb7ffa 100644 --- a/src/modules/fancyzones/tests/UnitTests/JsonHelpers.Tests.cpp +++ b/src/modules/fancyzones/tests/UnitTests/JsonHelpers.Tests.cpp @@ -1539,6 +1539,73 @@ namespace FancyZonesUnitTests compareJsonArrays(expected, actual); } + TEST_METHOD(QuickLayoutKeysParse) + { + const std::wstring zoneUuid = L"{33A2B101-06E0-437B-A61E-CDBECF502906}"; + LayoutQuickKeyJSON expected{ zoneUuid, 2 }; + json::JsonArray array; + array.Append(LayoutQuickKeyJSON::ToJson(expected)); + + json::JsonObject json; + json.SetNamedValue(L"quick-layout-keys", json::JsonValue::Parse(array.Stringify())); + + const auto& quickKeysMap = ParseQuickKeys(json); + + Assert::AreEqual((size_t)array.Size(), quickKeysMap.size()); + + Assert::IsTrue(quickKeysMap.find(zoneUuid) != quickKeysMap.end()); + int actualKey = quickKeysMap.find(zoneUuid)->second; + Assert::AreEqual((int)expected.key, actualKey); + } + + TEST_METHOD (QuickLayoutKeysParseEmpty) + { + json::JsonArray array; + json::JsonObject json; + json.SetNamedValue(L"quick-layout-keys", json::JsonValue::Parse(array.Stringify())); + + const auto& quickKeysMap = ParseQuickKeys(json); + + Assert::IsTrue(quickKeysMap.empty()); + } + + TEST_METHOD (QuickLayoutKeysParseInvalid) + { + const std::wstring invalidZoneUuid = L"{33A2B101-06E0-437B-}"; + LayoutQuickKeyJSON expected{ invalidZoneUuid, 2 }; + json::JsonArray array; + array.Append(LayoutQuickKeyJSON::ToJson(expected)); + + json::JsonObject json; + json.SetNamedValue(L"quick-layout-keys", json::JsonValue::Parse(array.Stringify())); + + const auto& quickKeysMap = ParseQuickKeys(json); + + Assert::IsTrue(quickKeysMap.empty()); + } + + TEST_METHOD (QuickLayoutKeysParseMissed) + { + json::JsonObject json; + + const auto& quickKeysMap = ParseQuickKeys(json); + + Assert::IsTrue(quickKeysMap.empty()); + } + + TEST_METHOD (QuickLayoutKeysSerialize) + { + json::JsonArray expected; + expected.Append(LayoutQuickKeyJSON::ToJson(LayoutQuickKeyJSON{ L"{33A2B101-06E0-437B-A61E-CDBECF502906}", 3})); + json::JsonObject json; + json.SetNamedValue(L"quick-layout-keys", json::JsonValue::Parse(expected.Stringify())); + + const auto& quickKeysMap = ParseQuickKeys(json); + + auto actual = SerializeQuickKeys(quickKeysMap); + compareJsonArrays(expected, actual); + } + TEST_METHOD (SetActiveZoneSet) { FancyZonesData data; @@ -1640,14 +1707,17 @@ namespace FancyZonesUnitTests }; AppZoneHistoryJSON appZoneHistory{ L"app-path", std::vector{ data } }; DeviceInfoJSON deviceInfo{ L"{33A2B101-06E0-437B-A61E-CDBECF502906}", DeviceInfoData{ ZoneSetData{ L"uuid", ZoneSetLayoutType::Custom }, true, 16, 3 } }; - json::JsonArray zoneSetsArray, appZonesArray, deviceInfoArray; + LayoutQuickKeyJSON quickKeys{ L"{33A2B101-06E0-437B-A61E-CDBECF502906}", 1 }; + json::JsonArray zoneSetsArray, appZonesArray, deviceInfoArray, quickKeysArray; zoneSetsArray.Append(CustomZoneSetJSON::ToJson(zoneSets)); appZonesArray.Append(AppZoneHistoryJSON::ToJson(appZoneHistory)); deviceInfoArray.Append(DeviceInfoJSON::ToJson(deviceInfo)); + quickKeysArray.Append(LayoutQuickKeyJSON::ToJson(quickKeys)); json::JsonObject fancyZones; fancyZones.SetNamedValue(L"custom-zone-sets", zoneSetsArray); fancyZones.SetNamedValue(L"app-zone-history", appZonesArray); fancyZones.SetNamedValue(L"devices", deviceInfoArray); + fancyZones.SetNamedValue(L"quick-layout-keys", quickKeysArray); json::to_file(jsonPath, fancyZones); @@ -1664,6 +1734,7 @@ namespace FancyZonesUnitTests Assert::IsFalse(fancyZonesData.GetCustomZoneSetsMap().empty()); Assert::IsFalse(fancyZonesData.GetCustomZoneSetsMap().empty()); Assert::IsFalse(fancyZonesData.GetCustomZoneSetsMap().empty()); + Assert::IsFalse(fancyZonesData.GetLayoutQuickKeys().empty()); } TEST_METHOD (LoadFancyZonesDataFromCroppedJson) @@ -1763,36 +1834,6 @@ namespace FancyZonesUnitTests compareJsonObjects(expectedJsonObj, actualJson); } - TEST_METHOD (SaveFancyZonesDataWithFastAccessLayoutKeys) - { - FancyZonesData data; - data.SetSettingsModulePath(m_moduleName); - const auto& jsonPath = data.zonesSettingsFileName; - - // json with fast-access-layout-keys - json::JsonObject expectedJsonObj; - json::JsonObject fastAccessKeyObj = json::JsonObject::Parse(L"{\"key\": 1, \"uuid\": \"{9AD7FC3A-0A6C-4373-B523-4958FC50C46C}\"}"); - json::JsonArray fastAccessKeysArray{}; - fastAccessKeysArray.Append(fastAccessKeyObj); - expectedJsonObj.SetNamedValue(L"devices", json::JsonArray{}); - expectedJsonObj.SetNamedValue(L"custom-zone-sets", json::JsonArray{}); - expectedJsonObj.SetNamedValue(L"fast-access-layout-keys", fastAccessKeysArray); - - // write json with fast-access-layout-keys to file - json::to_file(jsonPath, expectedJsonObj); - - data.SaveAppZoneHistoryAndZoneSettings(); - - // verify that file was written successfully - Assert::IsTrue(std::filesystem::exists(jsonPath)); - - // verify that fast-access-layout-keys were not changed after calling SaveFancyZonesData() - std::wstring str; - std::wifstream{ jsonPath, std::ios::binary } >> str; - json::JsonObject actualJson = json::JsonObject::Parse(str); - compareJsonObjects(expectedJsonObj, actualJson); - } - TEST_METHOD (AppLastZoneIndex) { const std::wstring deviceId = L"device-id";