Skip to content

Commit

Permalink
[FZ Editor] Layout hotkeys for quick swap UI: Parsing/serializing qui…
Browse files Browse the repository at this point in the history
…ck keys, telemetry (#10243)
  • Loading branch information
SeraphimaZykova committed Mar 18, 2021
1 parent 82420bb commit 3976271
Show file tree
Hide file tree
Showing 7 changed files with 174 additions and 43 deletions.
1 change: 1 addition & 0 deletions .github/actions/spell-check/expect.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2095,6 +2095,7 @@ Timeline
timeunion
timeutil
titlecase
TLayout
tlb
tlbimp
tmp
Expand Down
3 changes: 2 additions & 1 deletion src/modules/fancyzones/lib/FancyZonesData.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -536,6 +536,7 @@ void FancyZonesData::LoadFancyZonesData()
appZoneHistoryMap = JSONHelpers::ParseAppZoneHistory(fancyZonesDataJSON);
deviceInfoMap = JSONHelpers::ParseDeviceInfos(fancyZonesDataJSON);
customZoneSetsMap = JSONHelpers::ParseCustomZoneSets(fancyZonesDataJSON);
quickKeysMap = JSONHelpers::ParseQuickKeys(fancyZonesDataJSON);
}
}

Expand All @@ -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
Expand Down
8 changes: 8 additions & 0 deletions src/modules/fancyzones/lib/FancyZonesData.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,12 @@ class FancyZonesData

const std::unordered_map<std::wstring, std::vector<FancyZonesDataTypes::AppZoneHistoryData>>& GetAppZoneHistoryMap() const;

inline const JSONHelpers::TLayoutQuickKeysMap& GetLayoutQuickKeys() const
{
std::scoped_lock lock{ dataLock };
return quickKeysMap;
}

inline const std::wstring& GetZonesSettingsFileName() const
{
return zonesSettingsFileName;
Expand Down Expand Up @@ -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;
Expand Down
82 changes: 73 additions & 9 deletions src/modules/fancyzones/lib/JsonHelpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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> 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<int>(layoutQuickKey.GetNamedNumber(NonLocalizable::QuickAccessKey));

return result;
}
catch (const winrt::hresult_error&)
{
return std::nullopt;
}
}

json::JsonObject MonitorInfo::ToJson(const MonitorInfo& monitor)
{
json::JsonObject result{};
Expand Down Expand Up @@ -528,25 +562,19 @@ 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
{
if (before.has_value() && before->HasKey(NonLocalizable::Templates))
{
templates = before->GetNamedArray(NonLocalizable::Templates);
}

if (before.has_value() && before->HasKey(NonLocalizable::FastAccessLayoutKeys))
{
fastAccessLayoutKeys = before->GetNamedArray(NonLocalizable::FastAccessLayoutKeys);
}
}
catch (const winrt::hresult_error&)
{
Expand All @@ -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())
{
Expand Down Expand Up @@ -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;
}
}
15 changes: 14 additions & 1 deletion src/modules/fancyzones/lib/JsonHelpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,19 @@ namespace JSONHelpers
static std::optional<DeviceInfoJSON> FromJson(const json::JsonObject& device);
};

struct LayoutQuickKeyJSON
{
std::wstring layoutUuid;
int key;

static json::JsonObject ToJson(const LayoutQuickKeyJSON& device);
static std::optional<LayoutQuickKeyJSON> FromJson(const json::JsonObject& device);
};

using TAppZoneHistoryMap = std::unordered_map<std::wstring, std::vector<FancyZonesDataTypes::AppZoneHistoryData>>;
using TDeviceInfoMap = std::unordered_map<std::wstring, FancyZonesDataTypes::DeviceInfoData>;
using TCustomZoneSetsMap = std::unordered_map<std::wstring, FancyZonesDataTypes::CustomZoneSetData>;
using TLayoutQuickKeysMap = std::unordered_map<std::wstring, int>;

struct MonitorInfo
{
Expand All @@ -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);
Expand All @@ -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);
}
5 changes: 4 additions & 1 deletion src/modules/fancyzones/lib/trace.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -128,6 +129,7 @@ void Trace::FancyZones::DataChanged() noexcept
int appsHistorySize = static_cast<int>(data.GetAppZoneHistoryMap().size());
const auto& customZones = data.GetCustomZoneSetsMap();
const auto& devices = data.GetDeviceInfoMap();
const auto& quickKeys = data.GetLayoutQuickKeys();

std::unique_ptr<INT32[]> customZonesArray(new (std::nothrow) INT32[customZones.size()]);
if (!customZonesArray)
Expand Down Expand Up @@ -201,7 +203,8 @@ void Trace::FancyZones::DataChanged() noexcept
TraceLoggingInt32(static_cast<int>(customZones.size()), CustomZoneSetCountKey),
TraceLoggingInt32Array(customZonesArray.get(), static_cast<int>(customZones.size()), NumberOfZonesForEachCustomZoneSetKey),
TraceLoggingInt32(static_cast<int>(devices.size()), ActiveZoneSetsCountKey),
TraceLoggingWideString(activeZoneSetInfo.c_str(), ActiveZoneSetsListKey));
TraceLoggingWideString(activeZoneSetInfo.c_str(), ActiveZoneSetsListKey),
TraceLoggingInt32(static_cast<int>(quickKeys.size()), LayoutUsingQuickKeyCountKey));
}

void Trace::FancyZones::EditorLaunched(int value) noexcept
Expand Down
103 changes: 72 additions & 31 deletions src/modules/fancyzones/tests/UnitTests/JsonHelpers.Tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -1640,14 +1707,17 @@ namespace FancyZonesUnitTests
};
AppZoneHistoryJSON appZoneHistory{ L"app-path", std::vector<AppZoneHistoryData>{ 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);

Expand All @@ -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)
Expand Down Expand Up @@ -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";
Expand Down

0 comments on commit 3976271

Please sign in to comment.