NavCategory | Partial refactor and perf optimization (#1820)

* Partially refactor NavCategory

* Lazy load the states of GraphingMode Category

* code cleanup

* find_if to any_of

* remove Windows.System

* resolve warning WMC1507

* resolve comments

* fix indentations
This commit is contained in:
Tian L 2022-04-18 14:10:15 +08:00 committed by GitHub
parent 6a5b93cab6
commit 8e7ac87f01
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 913 additions and 981 deletions

View File

@ -75,7 +75,7 @@ void ApplicationViewModel::Categories::set(IObservableVector<NavCategoryGroup ^>
void ApplicationViewModel::Initialize(ViewMode mode)
{
if (!NavCategory::IsValidViewMode(mode) || !NavCategory::IsViewModeEnabled(mode))
if (!NavCategoryStates::IsValidViewMode(mode) || !NavCategoryStates::IsViewModeEnabled(mode))
{
mode = ViewMode::Standard;
}
@ -124,7 +124,7 @@ bool ApplicationViewModel::TryRecoverFromNavigationModeFailure()
void ApplicationViewModel::OnModeChanged()
{
assert(NavCategory::IsValidViewMode(m_mode));
assert(NavCategoryStates::IsValidViewMode(m_mode));
if (NavCategory::IsCalculatorViewMode(m_mode))
{
if (!m_CalculatorViewModel)
@ -160,15 +160,15 @@ void ApplicationViewModel::OnModeChanged()
}
auto resProvider = AppResourceProvider::GetInstance();
CategoryName = resProvider->GetResourceString(NavCategory::GetNameResourceKey(m_mode));
CategoryName = resProvider->GetResourceString(NavCategoryStates::GetNameResourceKey(m_mode));
// Cast mode to an int in order to save it to app data.
// Save the changed mode, so that the new window launches in this mode.
// Don't save until after we have adjusted to the new mode, so we don't save a mode that fails to load.
ApplicationData::Current->LocalSettings->Values->Insert(ModePropertyName, NavCategory::Serialize(m_mode));
ApplicationData::Current->LocalSettings->Values->Insert(ModePropertyName, NavCategoryStates::Serialize(m_mode));
// Log ModeChange event when not first launch, log WindowCreated on first launch
if (NavCategory::IsValidViewMode(m_PreviousMode))
if (NavCategoryStates::IsValidViewMode(m_PreviousMode))
{
TraceLogger::GetInstance()->LogModeChange(m_mode);
}
@ -213,7 +213,7 @@ void ApplicationViewModel::SetMenuCategories()
// Use the Categories property instead of the backing variable
// because we want to take advantage of binding updates and
// property setter logic.
Categories = NavCategoryGroup::CreateMenuOptions();
Categories = NavCategoryStates::CreateMenuOptions();
}
void ApplicationViewModel::ToggleAlwaysOnTop(float width, float height)

View File

@ -97,7 +97,7 @@ bool CopyPasteManager::HasStringToPaste()
String ^ CopyPasteManager::ValidatePasteExpression(String ^ pastedText, ViewMode mode, NumberBase programmerNumberBase, BitLength bitLengthType)
{
return ValidatePasteExpression(pastedText, mode, NavCategory::GetGroupType(mode), programmerNumberBase, bitLengthType);
return ValidatePasteExpression(pastedText, mode, NavCategoryStates::GetGroupType(mode), programmerNumberBase, bitLengthType);
}
// return "NoOp" if pastedText is invalid else return pastedText

View File

@ -13,7 +13,6 @@ using namespace CalculatorApp::ViewModel;
using namespace Concurrency;
using namespace Platform;
using namespace Platform::Collections;
using namespace std;
using namespace Windows::Foundation::Collections;
using namespace Windows::Management::Policies;
using namespace Windows::System;
@ -48,452 +47,230 @@ static constexpr int CURRENCY_ID = 16;
static constexpr int GRAPHING_ID = 17;
// ^^^ THESE CONSTANTS SHOULD NEVER CHANGE ^^^
wchar_t* towchar_t(int number)
namespace // put the utils within this TU
{
auto wstr = to_wstring(number);
return _wcsdup(wstr.c_str());
}
Platform::Agile<Windows::System::User^> CurrentUser;
std::mutex GraphingModeCheckMutex;
bool IsGraphingModeAvailable()
{
static bool supportGraph = Windows::Foundation::Metadata::ApiInformation::IsMethodPresent("Windows.UI.Text.RichEditTextDocument", "GetMath");
return supportGraph;
}
Box<bool> ^ _isGraphingModeEnabledCached = nullptr;
bool IsGraphingModeEnabled(User ^ currentUser = nullptr)
{
if (!IsGraphingModeAvailable())
bool IsGraphingModeEnabled()
{
return false;
}
static bool isChecked = false;
static bool isEnabled = false;
if (_isGraphingModeEnabledCached != nullptr)
{
return _isGraphingModeEnabledCached->Value;
}
if (!currentUser)
{
return true;
}
auto namedPolicyData = NamedPolicy::GetPolicyFromPathForUser(currentUser, L"Education", L"AllowGraphingCalculator");
_isGraphingModeEnabledCached = namedPolicyData->GetBoolean() == true;
return _isGraphingModeEnabledCached->Value;
}
// The order of items in this list determines the order of items in the menu.
static list<NavCategoryInitializer> s_categoryManifest = [] {
auto res = list<NavCategoryInitializer>{ NavCategoryInitializer{ ViewMode::Standard,
STANDARD_ID,
L"Standard",
L"StandardMode",
L"\uE8EF",
CategoryGroupType::Calculator,
MyVirtualKey::Number1,
L"1",
SUPPORTS_ALL,
true },
NavCategoryInitializer{ ViewMode::Scientific,
SCIENTIFIC_ID,
L"Scientific",
L"ScientificMode",
L"\uF196",
CategoryGroupType::Calculator,
MyVirtualKey::Number2,
L"2",
SUPPORTS_ALL,
true } };
int currentIndex = 3;
bool supportGraphingCalculator = IsGraphingModeAvailable();
if (supportGraphingCalculator)
{
bool isEnabled = IsGraphingModeEnabled();
res.push_back(NavCategoryInitializer{ ViewMode::Graphing,
GRAPHING_ID,
L"Graphing",
L"GraphingCalculatorMode",
L"\uF770",
CategoryGroupType::Calculator,
MyVirtualKey::Number3,
L"3",
SUPPORTS_ALL,
isEnabled });
++currentIndex;
}
res.insert(
res.end(),
{ NavCategoryInitializer{ ViewMode::Programmer,
PROGRAMMER_ID,
L"Programmer",
L"ProgrammerMode",
L"\uECCE",
CategoryGroupType::Calculator,
supportGraphingCalculator ? MyVirtualKey::Number4 : MyVirtualKey::Number3,
towchar_t(currentIndex++),
SUPPORTS_ALL,
true },
NavCategoryInitializer{ ViewMode::Date,
DATE_ID,
L"Date",
L"DateCalculationMode",
L"\uE787",
CategoryGroupType::Calculator,
supportGraphingCalculator ? MyVirtualKey::Number5 : MyVirtualKey::Number4,
towchar_t(currentIndex++),
SUPPORTS_ALL,
true },
NavCategoryInitializer{ ViewMode::Currency,
CURRENCY_ID,
L"Currency",
L"CategoryName_Currency",
L"\uEB0D",
CategoryGroupType::Converter,
MyVirtualKey::None,
nullptr,
POSITIVE_ONLY,
true },
NavCategoryInitializer{ ViewMode::Volume,
VOLUME_ID,
L"Volume",
L"CategoryName_Volume",
L"\uF1AA",
CategoryGroupType::Converter,
MyVirtualKey::None,
nullptr,
POSITIVE_ONLY,
true },
NavCategoryInitializer{ ViewMode::Length,
LENGTH_ID,
L"Length",
L"CategoryName_Length",
L"\uECC6",
CategoryGroupType::Converter,
MyVirtualKey::None,
nullptr,
POSITIVE_ONLY,
true },
NavCategoryInitializer{ ViewMode::Weight,
WEIGHT_ID,
L"Weight and Mass",
L"CategoryName_Weight",
L"\uF4C1",
CategoryGroupType::Converter,
MyVirtualKey::None,
nullptr,
POSITIVE_ONLY,
true },
NavCategoryInitializer{ ViewMode::Temperature,
TEMPERATURE_ID,
L"Temperature",
L"CategoryName_Temperature",
L"\uE7A3",
CategoryGroupType::Converter,
MyVirtualKey::None,
nullptr,
SUPPORTS_NEGATIVE,
true },
NavCategoryInitializer{ ViewMode::Energy,
ENERGY_ID,
L"Energy",
L"CategoryName_Energy",
L"\uECAD",
CategoryGroupType::Converter,
MyVirtualKey::None,
nullptr,
POSITIVE_ONLY,
true },
NavCategoryInitializer{ ViewMode::Area,
AREA_ID,
L"Area",
L"CategoryName_Area",
L"\uE809",
CategoryGroupType::Converter,
MyVirtualKey::None,
nullptr,
POSITIVE_ONLY,
true },
NavCategoryInitializer{ ViewMode::Speed,
SPEED_ID,
L"Speed",
L"CategoryName_Speed",
L"\uEADA",
CategoryGroupType::Converter,
MyVirtualKey::None,
nullptr,
POSITIVE_ONLY,
true },
NavCategoryInitializer{ ViewMode::Time,
TIME_ID,
L"Time",
L"CategoryName_Time",
L"\uE917",
CategoryGroupType::Converter,
MyVirtualKey::None,
nullptr,
POSITIVE_ONLY,
true },
NavCategoryInitializer{ ViewMode::Power,
POWER_ID,
L"Power",
L"CategoryName_Power",
L"\uE945",
CategoryGroupType::Converter,
MyVirtualKey::None,
nullptr,
SUPPORTS_NEGATIVE,
true },
NavCategoryInitializer{ ViewMode::Data,
DATA_ID,
L"Data",
L"CategoryName_Data",
L"\uF20F",
CategoryGroupType::Converter,
MyVirtualKey::None,
nullptr,
POSITIVE_ONLY,
true },
NavCategoryInitializer{ ViewMode::Pressure,
PRESSURE_ID,
L"Pressure",
L"CategoryName_Pressure",
L"\uEC4A",
CategoryGroupType::Converter,
MyVirtualKey::None,
nullptr,
POSITIVE_ONLY,
true },
NavCategoryInitializer{ ViewMode::Angle,
ANGLE_ID,
L"Angle",
L"CategoryName_Angle",
L"\uF515",
CategoryGroupType::Converter,
MyVirtualKey::None,
nullptr,
SUPPORTS_NEGATIVE,
true } });
return res;
}();
void NavCategory::InitializeCategoryManifest(User ^ user)
{
int i = 0;
for (NavCategoryInitializer category : s_categoryManifest)
{
if (category.viewMode == ViewMode::Graphing)
std::scoped_lock<std::mutex> lock(GraphingModeCheckMutex);
if (isChecked)
{
auto navCatInit = s_categoryManifest.begin();
std::advance(navCatInit, i);
(*navCatInit).isEnabled = IsGraphingModeEnabled(user);
break;
return isEnabled;
}
else
{
i++;
}
}
}
// This function should only be used when storing the mode to app data.
int NavCategory::Serialize(ViewMode mode)
{
auto iter =
find_if(begin(s_categoryManifest), end(s_categoryManifest), [mode](const NavCategoryInitializer& initializer) { return initializer.viewMode == mode; });
return (iter != s_categoryManifest.end()) ? iter->serializationId : -1;
}
// This function should only be used when restoring the mode from app data.
ViewMode NavCategory::Deserialize(Platform::Object ^ obj)
{
// If we cast directly to ViewMode we will fail
// because we technically store an int.
// Need to cast to int, then ViewMode.
auto boxed = dynamic_cast<Box<int> ^>(obj);
if (boxed != nullptr)
{
int serializationId = boxed->Value;
auto iter = find_if(begin(s_categoryManifest), end(s_categoryManifest), [serializationId](const NavCategoryInitializer& initializer) {
return initializer.serializationId == serializationId;
});
if (iter != s_categoryManifest.end())
{
if (iter->viewMode == ViewMode::Graphing)
{
// check if the user is allowed to use this feature
if (!IsGraphingModeEnabled())
{
return ViewMode::None;
}
}
return iter->viewMode;
auto namedPolicyData = NamedPolicy::GetPolicyFromPathForUser(
CurrentUser.Get(),
L"Education",
L"AllowGraphingCalculator");
isEnabled = namedPolicyData->GetBoolean();
isChecked = true;
return isEnabled;
}
}
return ViewMode::None;
}
// The order of items in this list determines the order of items in the menu.
const std::vector<NavCategoryInitializer> s_categoryManifest {
NavCategoryInitializer{ ViewMode::Standard,
STANDARD_ID,
L"Standard",
L"StandardMode",
L"\uE8EF",
CategoryGroupType::Calculator,
MyVirtualKey::Number1,
L"1",
SUPPORTS_ALL },
NavCategoryInitializer{ ViewMode::Scientific,
SCIENTIFIC_ID,
L"Scientific",
L"ScientificMode",
L"\uF196",
CategoryGroupType::Calculator,
MyVirtualKey::Number2,
L"2",
SUPPORTS_ALL },
NavCategoryInitializer{ ViewMode::Graphing,
GRAPHING_ID,
L"Graphing",
L"GraphingCalculatorMode",
L"\uF770",
CategoryGroupType::Calculator,
MyVirtualKey::Number3,
L"3",
SUPPORTS_ALL },
NavCategoryInitializer{ ViewMode::Programmer,
PROGRAMMER_ID,
L"Programmer",
L"ProgrammerMode",
L"\uECCE",
CategoryGroupType::Calculator,
MyVirtualKey::Number4,
L"4",
SUPPORTS_ALL },
NavCategoryInitializer{ ViewMode::Date,
DATE_ID,
L"Date",
L"DateCalculationMode",
L"\uE787",
CategoryGroupType::Calculator,
MyVirtualKey::Number5,
L"5",
SUPPORTS_ALL },
NavCategoryInitializer{ ViewMode::Currency,
CURRENCY_ID,
L"Currency",
L"CategoryName_Currency",
L"\uEB0D",
CategoryGroupType::Converter,
MyVirtualKey::None,
std::nullopt,
POSITIVE_ONLY },
NavCategoryInitializer{ ViewMode::Volume,
VOLUME_ID,
L"Volume",
L"CategoryName_Volume",
L"\uF1AA",
CategoryGroupType::Converter,
MyVirtualKey::None,
std::nullopt,
POSITIVE_ONLY },
NavCategoryInitializer{ ViewMode::Length,
LENGTH_ID,
L"Length",
L"CategoryName_Length",
L"\uECC6",
CategoryGroupType::Converter,
MyVirtualKey::None,
std::nullopt,
POSITIVE_ONLY },
NavCategoryInitializer{ ViewMode::Weight,
WEIGHT_ID,
L"Weight and Mass",
L"CategoryName_Weight",
L"\uF4C1",
CategoryGroupType::Converter,
MyVirtualKey::None,
std::nullopt,
POSITIVE_ONLY },
NavCategoryInitializer{ ViewMode::Temperature,
TEMPERATURE_ID,
L"Temperature",
L"CategoryName_Temperature",
L"\uE7A3",
CategoryGroupType::Converter,
MyVirtualKey::None,
std::nullopt,
SUPPORTS_NEGATIVE },
NavCategoryInitializer{ ViewMode::Energy,
ENERGY_ID,
L"Energy",
L"CategoryName_Energy",
L"\uECAD",
CategoryGroupType::Converter,
MyVirtualKey::None,
std::nullopt,
POSITIVE_ONLY },
NavCategoryInitializer{ ViewMode::Area,
AREA_ID,
L"Area",
L"CategoryName_Area",
L"\uE809",
CategoryGroupType::Converter,
MyVirtualKey::None,
std::nullopt,
POSITIVE_ONLY },
NavCategoryInitializer{ ViewMode::Speed,
SPEED_ID,
L"Speed",
L"CategoryName_Speed",
L"\uEADA",
CategoryGroupType::Converter,
MyVirtualKey::None,
std::nullopt,
POSITIVE_ONLY },
NavCategoryInitializer{ ViewMode::Time,
TIME_ID,
L"Time",
L"CategoryName_Time",
L"\uE917",
CategoryGroupType::Converter,
MyVirtualKey::None,
std::nullopt,
POSITIVE_ONLY },
NavCategoryInitializer{ ViewMode::Power,
POWER_ID,
L"Power",
L"CategoryName_Power",
L"\uE945",
CategoryGroupType::Converter,
MyVirtualKey::None,
std::nullopt,
SUPPORTS_NEGATIVE },
NavCategoryInitializer{ ViewMode::Data,
DATA_ID,
L"Data",
L"CategoryName_Data",
L"\uF20F",
CategoryGroupType::Converter,
MyVirtualKey::None,
std::nullopt,
POSITIVE_ONLY },
NavCategoryInitializer{ ViewMode::Pressure,
PRESSURE_ID,
L"Pressure",
L"CategoryName_Pressure",
L"\uEC4A",
CategoryGroupType::Converter,
MyVirtualKey::None,
std::nullopt,
POSITIVE_ONLY },
NavCategoryInitializer{ ViewMode::Angle,
ANGLE_ID,
L"Angle",
L"CategoryName_Angle",
L"\uF515",
CategoryGroupType::Converter,
MyVirtualKey::None,
std::nullopt,
SUPPORTS_NEGATIVE },
};
} // namespace unnamed
bool NavCategory::IsValidViewMode(ViewMode mode)
{
auto iter =
find_if(begin(s_categoryManifest), end(s_categoryManifest), [mode](const NavCategoryInitializer& initializer) { return initializer.viewMode == mode; });
return iter != s_categoryManifest.end();
}
bool NavCategory::IsViewModeEnabled(ViewMode mode)
{
auto iter = find_if(begin(s_categoryManifest), end(s_categoryManifest), [mode](const NavCategoryInitializer& initializer) {
return initializer.viewMode == mode && initializer.isEnabled;
});
return iter != s_categoryManifest.end();
}
bool NavCategory::IsCalculatorViewMode(ViewMode mode)
bool NavCategory::IsCalculatorViewMode(ViewModeType mode)
{
// Historically, Calculator modes are Standard, Scientific, and Programmer.
return !IsDateCalculatorViewMode(mode) && !IsGraphingCalculatorViewMode(mode) && IsModeInCategoryGroup(mode, CategoryGroupType::Calculator);
}
bool NavCategory::IsGraphingCalculatorViewMode(ViewMode mode)
bool NavCategory::IsGraphingCalculatorViewMode(ViewModeType mode)
{
return mode == ViewMode::Graphing;
return mode == ViewModeType::Graphing;
}
bool NavCategory::IsDateCalculatorViewMode(ViewMode mode)
bool NavCategory::IsDateCalculatorViewMode(ViewModeType mode)
{
return mode == ViewMode::Date;
return mode == ViewModeType::Date;
}
bool NavCategory::IsConverterViewMode(ViewMode mode)
bool NavCategory::IsConverterViewMode(ViewModeType mode)
{
return IsModeInCategoryGroup(mode, CategoryGroupType::Converter);
}
bool NavCategory::IsModeInCategoryGroup(ViewMode mode, CategoryGroupType type)
bool NavCategory::IsModeInCategoryGroup(ViewModeType mode, CategoryGroupType type)
{
auto iter = find_if(begin(s_categoryManifest), end(s_categoryManifest), [mode, type](const NavCategoryInitializer& initializer) {
return initializer.viewMode == mode && initializer.groupType == type;
});
return iter != s_categoryManifest.end();
}
String ^ NavCategory::GetFriendlyName(ViewMode mode)
{
auto iter =
find_if(begin(s_categoryManifest), end(s_categoryManifest), [mode](const NavCategoryInitializer& initializer) { return initializer.viewMode == mode; });
return (iter != s_categoryManifest.end()) ? StringReference(iter->friendlyName) : L"None";
}
ViewMode NavCategory::GetViewModeForFriendlyName(String ^ name)
{
auto iter = find_if(begin(s_categoryManifest), end(s_categoryManifest), [name](const NavCategoryInitializer& initializer) {
return wcscmp(initializer.friendlyName, name->Data()) == 0;
});
return (iter != s_categoryManifest.end()) ? iter->viewMode : ViewMode::None;
}
String ^ NavCategory::GetNameResourceKey(ViewMode mode)
{
auto iter =
find_if(begin(s_categoryManifest), end(s_categoryManifest), [mode](const NavCategoryInitializer& initializer) { return initializer.viewMode == mode; });
return (iter != s_categoryManifest.end()) ? StringReference(iter->nameResourceKey) + "Text" : nullptr;
}
CategoryGroupType NavCategory::GetGroupType(ViewMode mode)
{
auto iter =
find_if(begin(s_categoryManifest), end(s_categoryManifest), [mode](const NavCategoryInitializer& initializer) { return initializer.viewMode == mode; });
return (iter != s_categoryManifest.end()) ? iter->groupType : CategoryGroupType::None;
}
// GetIndex is 0-based, GetPosition is 1-based
int NavCategory::GetIndex(ViewMode mode)
{
int position = NavCategory::GetPosition(mode);
return max(-1, position - 1);
}
int NavCategory::GetFlatIndex(ViewMode mode)
{
int index = -1;
CategoryGroupType type = CategoryGroupType::None;
auto iter = find_if(begin(s_categoryManifest), end(s_categoryManifest), [mode, &type, &index](const NavCategoryInitializer& initializer) {
index++;
if (initializer.groupType != type)
{
type = initializer.groupType;
index++;
}
return initializer.viewMode == mode;
});
return (iter != s_categoryManifest.end()) ? index : -1;
}
// GetIndex is 0-based, GetPosition is 1-based
int NavCategory::GetIndexInGroup(ViewMode mode, CategoryGroupType type)
{
int index = -1;
auto iter = find_if(begin(s_categoryManifest), end(s_categoryManifest), [mode, type, &index](const NavCategoryInitializer& initializer) {
if (initializer.groupType == type)
{
index++;
return initializer.viewMode == mode;
}
return false;
});
return (iter != s_categoryManifest.end()) ? index : -1;
}
// GetIndex is 0-based, GetPosition is 1-based
int NavCategory::GetPosition(ViewMode mode)
{
int position = 0;
auto iter = find_if(begin(s_categoryManifest), end(s_categoryManifest), [mode, &position](const NavCategoryInitializer& initializer) {
position++;
return initializer.viewMode == mode;
});
return (iter != s_categoryManifest.end()) ? position : -1;
}
ViewMode NavCategory::GetViewModeForVirtualKey(MyVirtualKey virtualKey)
{
auto iter = find_if(begin(s_categoryManifest), end(s_categoryManifest), [virtualKey](const NavCategoryInitializer& initializer) {
return initializer.virtualKey == virtualKey;
});
return (iter != s_categoryManifest.end()) ? iter->viewMode : ViewMode::None;
}
void NavCategory::GetCategoryAcceleratorKeys(IVector<MyVirtualKey> ^ accelerators)
{
if (accelerators != nullptr)
{
accelerators->Clear();
for (auto category : s_categoryManifest)
{
if (category.virtualKey != MyVirtualKey::None)
{
accelerators->Append(category.virtualKey);
}
}
}
return std::any_of(
s_categoryManifest.cbegin(),
s_categoryManifest.cend(),
[mode, type](const auto& initializer) {
return initializer.viewMode == mode && initializer.groupType == type;
});
}
NavCategoryGroup::NavCategoryGroup(const NavCategoryGroupInitializer& groupInitializer)
@ -523,33 +300,225 @@ NavCategoryGroup::NavCategoryGroup(const NavCategoryGroupInitializer& groupIniti
categoryName,
categoryAutomationName,
StringReference(categoryInitializer.glyph),
categoryInitializer.accessKey != nullptr ? ref new String(categoryInitializer.accessKey)
categoryInitializer.accessKey.has_value() ? ref new String(categoryInitializer.accessKey->c_str())
: resProvider->GetResourceString(nameResourceKey + "AccessKey"),
groupMode,
categoryInitializer.viewMode,
categoryInitializer.supportsNegative,
categoryInitializer.isEnabled));
categoryInitializer.viewMode != ViewMode::Graphing));
}
}
}
IObservableVector<NavCategoryGroup ^> ^ NavCategoryGroup::CreateMenuOptions()
void NavCategoryStates::SetCurrentUser(Windows::System::User^ user)
{
std::scoped_lock<std::mutex> lock(GraphingModeCheckMutex);
CurrentUser = user;
}
IObservableVector<NavCategoryGroup ^> ^ NavCategoryStates::CreateMenuOptions()
{
auto menuOptions = ref new Vector<NavCategoryGroup ^>();
menuOptions->Append(CreateCalculatorCategory());
menuOptions->Append(CreateConverterCategory());
menuOptions->Append(CreateCalculatorCategoryGroup());
menuOptions->Append(CreateConverterCategoryGroup());
return menuOptions;
}
NavCategoryGroup ^ NavCategoryGroup::CreateCalculatorCategory()
NavCategoryGroup ^ NavCategoryStates::CreateCalculatorCategoryGroup()
{
return ref new NavCategoryGroup(
NavCategoryGroupInitializer{ CategoryGroupType::Calculator, L"CalculatorModeTextCaps", L"CalculatorModeText", L"CalculatorModePluralText" });
}
NavCategoryGroup ^ NavCategoryGroup::CreateConverterCategory()
NavCategoryGroup ^ NavCategoryStates::CreateConverterCategoryGroup()
{
return ref new NavCategoryGroup(
NavCategoryGroupInitializer{ CategoryGroupType::Converter, L"ConverterModeTextCaps", L"ConverterModeText", L"ConverterModePluralText" });
}
// This function should only be used when storing the mode to app data.
int NavCategoryStates::Serialize(ViewMode mode)
{
const auto& citer = find_if(
cbegin(s_categoryManifest),
cend(s_categoryManifest),
[mode](const auto& initializer) { return initializer.viewMode == mode; });
return (citer != s_categoryManifest.cend()) ? citer->serializationId : -1;
}
// This function should only be used when restoring the mode from app data.
ViewMode NavCategoryStates::Deserialize(Platform::Object ^ obj)
{
// If we cast directly to ViewMode we will fail
// because we technically store an int.
// Need to cast to int, then ViewMode.
auto boxed = dynamic_cast<Box<int> ^>(obj);
if (boxed != nullptr)
{
int serializationId = boxed->Value;
const auto& citer = find_if(
cbegin(s_categoryManifest),
cend(s_categoryManifest),
[serializationId](const auto& initializer) { return initializer.serializationId == serializationId; });
return citer != s_categoryManifest.cend() ?
(citer->viewMode == ViewMode::Graphing ?
(IsGraphingModeEnabled() ? citer->viewMode : ViewMode::None)
: citer->viewMode)
: ViewMode::None;
}
else
{
return ViewMode::None;
}
}
ViewMode NavCategoryStates::GetViewModeForFriendlyName(String ^ name)
{
const auto& citer = find_if(
cbegin(s_categoryManifest),
cend(s_categoryManifest),
[name](const auto& initializer) { return wcscmp(initializer.friendlyName, name->Data()) == 0; });
return (citer != s_categoryManifest.cend()) ? citer->viewMode : ViewMode::None;
}
String ^ NavCategoryStates::GetFriendlyName(ViewMode mode)
{
const auto& citer = find_if(
cbegin(s_categoryManifest),
cend(s_categoryManifest),
[mode](const auto& initializer) { return initializer.viewMode == mode; });
return (citer != s_categoryManifest.cend()) ? StringReference(citer->friendlyName) : L"None";
}
String ^ NavCategoryStates::GetNameResourceKey(ViewMode mode)
{
const auto& citer = find_if(
cbegin(s_categoryManifest),
cend(s_categoryManifest),
[mode](const auto& initializer) { return initializer.viewMode == mode; });
return (citer != s_categoryManifest.cend()) ? StringReference(citer->nameResourceKey) + "Text" : nullptr;
}
CategoryGroupType NavCategoryStates::GetGroupType(ViewMode mode)
{
const auto& citer = find_if(
cbegin(s_categoryManifest),
cend(s_categoryManifest),
[mode](const auto& initializer) { return initializer.viewMode == mode; });
return (citer != s_categoryManifest.cend()) ? citer->groupType : CategoryGroupType::None;
}
// GetIndex is 0-based, GetPosition is 1-based
int NavCategoryStates::GetIndex(ViewMode mode)
{
int position = GetPosition(mode);
return std::max(-1, position - 1);
}
int NavCategoryStates::GetFlatIndex(ViewMode mode)
{
int index = -1;
CategoryGroupType type = CategoryGroupType::None;
const auto& citer = find_if(
cbegin(s_categoryManifest),
cend(s_categoryManifest),
[mode, &type, &index](const auto& initializer) {
++index;
if (initializer.groupType != type)
{
type = initializer.groupType;
++index;
}
return initializer.viewMode == mode;
});
return (citer != s_categoryManifest.cend()) ? index : -1;
}
// GetIndex is 0-based, GetPosition is 1-based
int NavCategoryStates::GetIndexInGroup(ViewMode mode, CategoryGroupType type)
{
int index = -1;
const auto& citer = find_if(
cbegin(s_categoryManifest),
cend(s_categoryManifest),
[mode, type, &index](const auto& initializer) {
if (initializer.groupType == type)
{
++index;
return initializer.viewMode == mode;
}
return false;
});
return (citer != s_categoryManifest.cend()) ? index : -1;
}
// GetIndex is 0-based, GetPosition is 1-based
int NavCategoryStates::GetPosition(ViewMode mode)
{
int position = 0;
const auto& citer = find_if(
cbegin(s_categoryManifest),
cend(s_categoryManifest),
[mode, &position](const auto& initializer) {
++position;
return initializer.viewMode == mode;
});
return (citer != s_categoryManifest.cend()) ? position : -1;
}
ViewMode NavCategoryStates::GetViewModeForVirtualKey(MyVirtualKey virtualKey)
{
const auto& citer = find_if(
cbegin(s_categoryManifest),
cend(s_categoryManifest),
[virtualKey](const auto& initializer) { return initializer.virtualKey == virtualKey; });
return (citer != s_categoryManifest.end()) ? citer->viewMode : ViewMode::None;
}
void NavCategoryStates::GetCategoryAcceleratorKeys(IVector<MyVirtualKey> ^ accelerators)
{
if (accelerators != nullptr)
{
accelerators->Clear();
for (const auto& category : s_categoryManifest)
{
if (category.virtualKey != MyVirtualKey::None)
{
accelerators->Append(category.virtualKey);
}
}
}
}
bool NavCategoryStates::IsValidViewMode(ViewMode mode)
{
const auto& citer = find_if(
cbegin(s_categoryManifest),
cend(s_categoryManifest),
[mode](const auto& initializer) { return initializer.viewMode == mode; });
return citer != s_categoryManifest.cend();
}
bool NavCategoryStates::IsViewModeEnabled(ViewMode mode)
{
if (mode != ViewMode::Graphing)
{
return true;
}
else
{
return IsGraphingModeEnabled();
}
}

View File

@ -59,46 +59,21 @@ namespace CalculatorApp::ViewModel
private
struct NavCategoryInitializer
{
constexpr NavCategoryInitializer(
ViewMode mode,
int id,
wchar_t const* name,
wchar_t const* nameKey,
wchar_t const* glyph,
CategoryGroupType group,
MyVirtualKey vKey,
wchar_t const* aKey,
bool categorySupportsNegative,
bool enabled)
: viewMode(mode)
, serializationId(id)
, friendlyName(name)
, nameResourceKey(nameKey)
, glyph(glyph)
, groupType(group)
, virtualKey(vKey)
, accessKey(aKey)
, supportsNegative(categorySupportsNegative)
, isEnabled(enabled)
{
}
const ViewMode viewMode;
const int serializationId;
const wchar_t* const friendlyName;
const wchar_t* const nameResourceKey;
const wchar_t* const glyph;
const CategoryGroupType groupType;
const MyVirtualKey virtualKey;
const wchar_t* const accessKey;
const bool supportsNegative;
bool isEnabled;
ViewMode viewMode;
int serializationId;
const wchar_t* friendlyName;
const wchar_t* nameResourceKey;
const wchar_t* glyph;
CategoryGroupType groupType;
MyVirtualKey virtualKey;
std::optional<std::wstring> accessKey;
bool supportsNegative;
};
private
struct NavCategoryGroupInitializer
{
constexpr NavCategoryGroupInitializer(CategoryGroupType t, wchar_t const* h, wchar_t const* n, wchar_t const* a)
NavCategoryGroupInitializer(CategoryGroupType t, wchar_t const* h, wchar_t const* n, wchar_t const* a)
: type(t)
, headerResourceKey(h)
, modeResourceKey(n)
@ -112,36 +87,85 @@ namespace CalculatorApp::ViewModel
const wchar_t* automationResourceKey;
};
[Windows::UI::Xaml::Data::Bindable] public ref class NavCategory sealed : public Windows::UI::Xaml::Data::INotifyPropertyChanged
[Windows::UI::Xaml::Data::Bindable]
public ref class NavCategory sealed : public Windows::UI::Xaml::Data::INotifyPropertyChanged
{
private:
using ViewModeType = ::CalculatorApp::ViewModel::Common::ViewMode;
public:
OBSERVABLE_OBJECT();
PROPERTY_R(Platform::String ^, Name);
PROPERTY_R(Platform::String ^, AutomationName);
PROPERTY_R(Platform::String ^, Glyph);
PROPERTY_R(ViewMode, Mode);
PROPERTY_R(ViewModeType, ViewMode);
PROPERTY_R(Platform::String ^, AccessKey);
PROPERTY_R(bool, SupportsNegative);
PROPERTY_R(bool, IsEnabled);
PROPERTY_RW(bool, IsEnabled);
property Platform::String
^ AutomationId { Platform::String ^ get() { return m_Mode.ToString(); } }
^ AutomationId { Platform::String ^ get() { return m_ViewMode.ToString(); } }
static bool IsCalculatorViewMode(ViewModeType mode);
static bool IsGraphingCalculatorViewMode(ViewModeType mode);
static bool IsDateCalculatorViewMode(ViewModeType mode);
static bool IsConverterViewMode(ViewModeType mode);
internal : NavCategory(
Platform::String ^ name,
Platform::String ^ automationName,
Platform::String ^ glyph,
Platform::String ^ accessKey,
Platform::String ^ mode,
ViewModeType viewMode,
bool supportsNegative,
bool isEnabled)
: m_Name(name)
, m_AutomationName(automationName)
, m_Glyph(glyph)
, m_AccessKey(accessKey)
, m_modeString(mode)
, m_ViewMode(viewMode)
, m_SupportsNegative(supportsNegative)
, m_IsEnabled(isEnabled)
{
}
private:
static bool IsModeInCategoryGroup(ViewModeType mode, CategoryGroupType groupType);
Platform::String ^ m_modeString;
};
[Windows::UI::Xaml::Data::Bindable]
public ref class NavCategoryGroup sealed : public Windows::UI::Xaml::Data::INotifyPropertyChanged
{
internal:
NavCategoryGroup(const NavCategoryGroupInitializer& groupInitializer);
public:
OBSERVABLE_OBJECT();
OBSERVABLE_PROPERTY_R(Platform::String ^, Name);
OBSERVABLE_PROPERTY_R(Platform::String ^, AutomationName);
OBSERVABLE_PROPERTY_R(CategoryGroupType, GroupType);
OBSERVABLE_PROPERTY_R(Windows::Foundation::Collections::IObservableVector<NavCategory ^> ^, Categories);
};
public ref class NavCategoryStates sealed
{
public:
static void SetCurrentUser(Windows::System::User^ user);
static Windows::Foundation::Collections::IObservableVector<NavCategoryGroup ^> ^ CreateMenuOptions();
static NavCategoryGroup ^ CreateCalculatorCategoryGroup();
static NavCategoryGroup ^ CreateConverterCategoryGroup();
static bool IsValidViewMode(ViewMode mode);
static bool IsViewModeEnabled(ViewMode mode);
// For saving/restoring last mode used.
static int Serialize(ViewMode mode);
static ViewMode Deserialize(Platform::Object ^ obj);
// Query properties from states
static ViewMode GetViewModeForFriendlyName(Platform::String ^ name);
static bool IsValidViewMode(ViewMode mode);
static bool IsViewModeEnabled(ViewMode mode);
static bool IsCalculatorViewMode(ViewMode mode);
static bool IsGraphingCalculatorViewMode(ViewMode mode);
static bool IsDateCalculatorViewMode(ViewMode mode);
static bool IsConverterViewMode(ViewMode mode);
static void InitializeCategoryManifest(Windows::System::User ^ user);
static Platform::String ^ GetFriendlyName(ViewMode mode);
static Platform::String ^ GetNameResourceKey(ViewMode mode);
static CategoryGroupType GetGroupType(ViewMode mode);
@ -152,51 +176,9 @@ namespace CalculatorApp::ViewModel
static int GetIndexInGroup(ViewMode mode, CategoryGroupType type);
static int GetPosition(ViewMode mode);
// Virtual key related
static ViewMode GetViewModeForVirtualKey(MyVirtualKey virtualKey);
static void GetCategoryAcceleratorKeys(Windows::Foundation::Collections::IVector<MyVirtualKey> ^ resutls);
internal : NavCategory(
Platform::String ^ name,
Platform::String ^ automationName,
Platform::String ^ glyph,
Platform::String ^ accessKey,
Platform::String ^ mode,
ViewMode viewMode,
bool supportsNegative,
bool isEnabled)
: m_Name(name)
, m_AutomationName(automationName)
, m_Glyph(glyph)
, m_AccessKey(accessKey)
, m_modeString(mode)
, m_Mode(viewMode)
, m_SupportsNegative(supportsNegative)
, m_IsEnabled(isEnabled)
{
}
private:
static bool IsModeInCategoryGroup(ViewMode mode, CategoryGroupType groupType);
Platform::String ^ m_modeString;
};
[Windows::UI::Xaml::Data::Bindable] public ref class NavCategoryGroup sealed : public Windows::UI::Xaml::Data::INotifyPropertyChanged
{
public:
OBSERVABLE_OBJECT();
OBSERVABLE_PROPERTY_R(Platform::String ^, Name);
OBSERVABLE_PROPERTY_R(Platform::String ^, AutomationName);
OBSERVABLE_PROPERTY_R(CategoryGroupType, GroupType);
OBSERVABLE_PROPERTY_R(Windows::Foundation::Collections::IObservableVector<NavCategory ^> ^, Categories);
static Windows::Foundation::Collections::IObservableVector<NavCategoryGroup ^> ^ CreateMenuOptions();
static NavCategoryGroup ^ CreateCalculatorCategory();
static NavCategoryGroup ^ CreateConverterCategory();
private:
NavCategoryGroup(const NavCategoryGroupInitializer& groupInitializer);
};
}
}

View File

@ -79,7 +79,7 @@ namespace CalculatorApp
{
auto fields = ref new LoggingFields();
fields->AddString(StringReference(CALC_MODE), NavCategory::GetFriendlyName(mode));
fields->AddString(StringReference(CALC_MODE), NavCategoryStates::GetFriendlyName(mode));
fields->AddString(StringReference(L"VisualState"), state);
fields->AddBoolean(StringReference(L"IsAlwaysOnTop"), isAlwaysOnTop);
TraceLoggingCommon::GetInstance()->LogLevel2Event(StringReference(EVENT_NAME_VISUAL_STATE_CHANGED), fields);
@ -94,18 +94,18 @@ namespace CalculatorApp
}
auto fields = ref new LoggingFields();
fields->AddString(StringReference(CALC_MODE), NavCategory::GetFriendlyName(mode));
fields->AddString(StringReference(CALC_MODE), NavCategoryStates::GetFriendlyName(mode));
fields->AddUInt64(StringReference(L"NumOfOpenWindows"), currentWindowCount);
TraceLoggingCommon::GetInstance()->LogLevel2Event(StringReference(EVENT_NAME_WINDOW_ON_CREATED), fields);
}
void TraceLogger::LogModeChange(ViewMode mode)
{
if (NavCategory::IsValidViewMode(mode))
if (NavCategoryStates::IsValidViewMode(mode))
{
auto fields = ref new LoggingFields();
;
fields->AddString(StringReference(CALC_MODE), NavCategory::GetFriendlyName(mode));
fields->AddString(StringReference(CALC_MODE), NavCategoryStates::GetFriendlyName(mode));
TraceLoggingCommon::GetInstance()->LogLevel2Event(StringReference(EVENT_NAME_MODE_CHANGED), fields);
}
}
@ -113,7 +113,7 @@ namespace CalculatorApp
void TraceLogger::LogHistoryItemLoad(ViewMode mode, int historyListSize, int loadedIndex)
{
auto fields = ref new LoggingFields();
fields->AddString(StringReference(CALC_MODE), NavCategory::GetFriendlyName(mode));
fields->AddString(StringReference(CALC_MODE), NavCategoryStates::GetFriendlyName(mode));
fields->AddInt32(StringReference(L"HistoryListSize"), historyListSize);
fields->AddInt32(StringReference(L"HistoryItemIndex"), loadedIndex);
TraceLoggingCommon::GetInstance()->LogLevel2Event(StringReference(EVENT_NAME_HISTORY_ITEM_LOAD), fields);
@ -122,7 +122,7 @@ namespace CalculatorApp
void TraceLogger::LogMemoryItemLoad(ViewMode mode, int memoryListSize, int loadedIndex)
{
auto fields = ref new LoggingFields();
fields->AddString(StringReference(CALC_MODE), NavCategory::GetFriendlyName(mode));
fields->AddString(StringReference(CALC_MODE), NavCategoryStates::GetFriendlyName(mode));
fields->AddInt32(StringReference(L"MemoryListSize"), memoryListSize);
fields->AddInt32(StringReference(L"MemoryItemIndex"), loadedIndex);
TraceLoggingCommon::GetInstance()->LogLevel2Event(StringReference(EVENT_NAME_MEMORY_ITEM_LOAD), fields);
@ -131,7 +131,7 @@ namespace CalculatorApp
void TraceLogger::LogError(ViewMode mode, Platform::String ^ functionName, Platform::String ^ errorString)
{
auto fields = ref new LoggingFields();
fields->AddString(StringReference(CALC_MODE), NavCategory::GetFriendlyName(mode));
fields->AddString(StringReference(CALC_MODE), NavCategoryStates::GetFriendlyName(mode));
fields->AddString(StringReference(L"FunctionName"), functionName);
fields->AddString(StringReference(L"Message"), errorString);
TraceLoggingCommon::GetInstance()->LogLevel2Event(StringReference(EVENT_NAME_EXCEPTION), fields);
@ -140,7 +140,7 @@ namespace CalculatorApp
void TraceLogger::LogStandardException(ViewMode mode, wstring_view functionName, const exception& e)
{
auto fields = ref new LoggingFields();
fields->AddString(StringReference(CALC_MODE), NavCategory::GetFriendlyName(mode));
fields->AddString(StringReference(CALC_MODE), NavCategoryStates::GetFriendlyName(mode));
fields->AddString(StringReference(L"FunctionName"), StringReference(functionName.data()));
wstringstream exceptionMessage;
exceptionMessage << e.what();
@ -151,7 +151,7 @@ namespace CalculatorApp
void TraceLogger::LogPlatformExceptionInfo(CalculatorApp::ViewModel::Common::ViewMode mode, Platform::String ^ functionName, Platform::String^ message, int hresult)
{
auto fields = ref new LoggingFields();
fields->AddString(StringReference(CALC_MODE), NavCategory::GetFriendlyName(mode));
fields->AddString(StringReference(CALC_MODE), NavCategoryStates::GetFriendlyName(mode));
fields->AddString(StringReference(L"FunctionName"), functionName);
fields->AddString(StringReference(L"Message"), message);
fields->AddInt32(StringReference(L"HRESULT"), hresult);
@ -223,7 +223,7 @@ namespace CalculatorApp
Platform::String ^ buttonUsageString;
for (size_t i = 0; i < buttonLog.size(); i++)
{
buttonUsageString += NavCategory::GetFriendlyName(buttonLog[i].mode);
buttonUsageString += NavCategoryStates::GetFriendlyName(buttonLog[i].mode);
buttonUsageString += "|";
buttonUsageString += buttonLog[i].button.ToString();
buttonUsageString += "|";
@ -245,7 +245,7 @@ namespace CalculatorApp
{
const wchar_t* calculationType = AddSubtractMode ? L"AddSubtractMode" : L"DateDifferenceMode";
auto fields = ref new LoggingFields();
fields->AddString(StringReference(CALC_MODE), NavCategory::GetFriendlyName(ViewMode::Date));
fields->AddString(StringReference(CALC_MODE), NavCategoryStates::GetFriendlyName(ViewMode::Date));
fields->AddString(StringReference(L"CalculationType"), StringReference(calculationType));
TraceLoggingCommon::GetInstance()->LogLevel2Event(StringReference(EVENT_NAME_DATE_CALCULATION_MODE_USED), fields);
}
@ -253,7 +253,7 @@ namespace CalculatorApp
void TraceLogger::LogConverterInputReceived(ViewMode mode)
{
auto fields = ref new LoggingFields();
fields->AddString(StringReference(CALC_MODE), NavCategory::GetFriendlyName(mode));
fields->AddString(StringReference(CALC_MODE), NavCategoryStates::GetFriendlyName(mode));
TraceLoggingCommon::GetInstance()->LogLevel2Event(StringReference(EVENT_NAME_CONVERTER_INPUT_RECEIVED), fields);
}
@ -266,7 +266,7 @@ namespace CalculatorApp
void TraceLogger::LogInputPasted(ViewMode mode)
{
auto fields = ref new LoggingFields();
fields->AddString(StringReference(CALC_MODE), NavCategory::GetFriendlyName(mode));
fields->AddString(StringReference(CALC_MODE), NavCategoryStates::GetFriendlyName(mode));
TraceLoggingCommon::GetInstance()->LogLevel2Event(StringReference(EVENT_NAME_INPUT_PASTED), fields);
}

View File

@ -240,7 +240,7 @@ unordered_map<UCM::Unit, UCM::ConversionData, UCM::UnitHash> CurrencyDataLoader:
bool CurrencyDataLoader::SupportsCategory(const UCM::Category& target)
{
static int currencyId = NavCategory::Serialize(ViewMode::Currency);
static int currencyId = NavCategoryStates::Serialize(ViewMode::Currency);
return target.id == currencyId;
}

View File

@ -53,7 +53,7 @@ bool UnitConverterDataLoader::SupportsCategory(const UCM::Category& target)
GetCategories(supportedCategories);
}
static int currencyId = NavCategory::Serialize(ViewMode::Currency);
static int currencyId = NavCategoryStates::Serialize(ViewMode::Currency);
auto itr = find_if(supportedCategories->begin(), supportedCategories->end(), [&](const UCM::Category& category) {
return currencyId != category.id && target.id == category.id;
});
@ -79,7 +79,7 @@ void UnitConverterDataLoader::LoadData()
this->m_ratioMap->clear();
for (UCM::Category objectCategory : *m_categoryList)
{
ViewMode categoryViewMode = NavCategory::Deserialize(objectCategory.id);
ViewMode categoryViewMode = NavCategoryStates::Deserialize(objectCategory.id);
assert(NavCategory::IsConverterViewMode(categoryViewMode));
if (categoryViewMode == ViewMode::Currency)
{
@ -148,11 +148,11 @@ void UnitConverterDataLoader::LoadData()
void UnitConverterDataLoader::GetCategories(_In_ shared_ptr<vector<UCM::Category>> categoriesList)
{
categoriesList->clear();
auto converterCategory = NavCategoryGroup::CreateConverterCategory();
auto converterCategory = NavCategoryStates::CreateConverterCategoryGroup();
for (auto const& category : converterCategory->Categories)
{
/* Id, CategoryName, SupportsNegative */
categoriesList->emplace_back(NavCategory::Serialize(category->Mode), category->Name->Data(), category->SupportsNegative);
categoriesList->emplace_back(NavCategoryStates::Serialize(category->ViewMode), category->Name->Data(), category->SupportsNegative);
}
}

View File

@ -719,7 +719,7 @@ void StandardCalculatorViewModel::OnPasteCommand(Object ^ parameter)
}
// Ensure that the paste happens on the UI thread
create_task(CopyPasteManager::GetStringToPaste(mode, NavCategory::GetGroupType(mode), numberBase, bitLengthType))
create_task(CopyPasteManager::GetStringToPaste(mode, NavCategoryStates::GetGroupType(mode), numberBase, bitLengthType))
.then([that, mode](String ^ pastedString) { that->OnPaste(pastedString); }, concurrency::task_continuation_context::use_current());
}

View File

@ -537,7 +537,7 @@ void UnitConverterViewModel::OnPasteCommand(Platform::Object ^ parameter)
// Any converter ViewMode is fine here.
auto that(this);
create_task(CopyPasteManager::GetStringToPaste(m_Mode, NavCategory::GetGroupType(m_Mode), NumberBase::Unknown, BitLength::BitLengthUnknown))
create_task(CopyPasteManager::GetStringToPaste(m_Mode, NavCategoryStates::GetGroupType(m_Mode), NumberBase::Unknown, BitLength::BitLengthUnknown))
.then([that](String ^ pastedString) { that->OnPaste(pastedString); }, concurrency::task_continuation_context::use_current());
}

View File

@ -203,7 +203,7 @@ namespace CalculatorApp
if (value != nullptr)
{
auto currentCategory = value->GetModelCategory();
IsCurrencyCurrentCategory = currentCategory.id == CalculatorApp::ViewModel::Common::NavCategory::Serialize(CalculatorApp::ViewModel::Common::ViewMode::Currency);
IsCurrencyCurrentCategory = currentCategory.id == CalculatorApp::ViewModel::Common::NavCategoryStates::Serialize(CalculatorApp::ViewModel::Common::ViewMode::Currency);
}
RaisePropertyChanged("CurrentCategory");
}

View File

@ -85,7 +85,11 @@ protected override void OnLaunched(LaunchActivatedEventArgs args)
// If the app got pre-launch activated, then save that state in a flag
m_preLaunched = true;
}
NavCategory.InitializeCategoryManifest(args.User);
NavCategoryStates.SetCurrentUser(args.User);
// It takes time to check GraphingMode at the 1st time. So, do it in a background thread
Task.Run(() => NavCategoryStates.IsViewModeEnabled(ViewMode.Graphing));
OnAppLaunch(args, args.Arguments);
}
@ -403,7 +407,7 @@ private async Task SetupJumpList()
{
try
{
var calculatorOptions = NavCategoryGroup.CreateCalculatorCategory();
var calculatorOptions = NavCategoryStates.CreateCalculatorCategoryGroup();
var jumpList = await JumpList.LoadCurrentAsync();
jumpList.SystemGroupKind = JumpListSystemGroupKind.None;
@ -411,13 +415,13 @@ private async Task SetupJumpList()
foreach (NavCategory option in calculatorOptions.Categories)
{
if (!option.IsEnabled)
if (!NavCategoryStates.IsViewModeEnabled(option.ViewMode))
{
continue;
}
ViewMode mode = option.Mode;
var item = JumpListItem.CreateWithArguments(((int)mode).ToString(), "ms-resource:///Resources/" + NavCategory.GetNameResourceKey(mode));
item.Description = "ms-resource:///Resources/" + NavCategory.GetNameResourceKey(mode);
ViewMode mode = option.ViewMode;
var item = JumpListItem.CreateWithArguments(((int)mode).ToString(), "ms-resource:///Resources/" + NavCategoryStates.GetNameResourceKey(mode));
item.Description = "ms-resource:///Resources/" + NavCategoryStates.GetNameResourceKey(mode);
item.Logo = new Uri("ms-appx:///Assets/" + mode.ToString() + ".png");
jumpList.Items.Add(item);

View File

@ -165,11 +165,12 @@
<Compile Include="Converters\ItemSizeToVisibilityConverter.cs" />
<Compile Include="Converters\RadixToStringConverter.cs" />
<Compile Include="Converters\VisibilityNegationConverter.cs" />
<Compile Include="Selectors\NavViewMenuItemTemplateSelector.cs" />
<Compile Include="Utils\ThemeHelper.cs" />
<Compile Include="Views\GraphingCalculator\EquationStylePanelControl.xaml.cs">
<DependentUpon>EquationStylePanelControl.xaml</DependentUpon>
</Compile>
<Compile Include="Views\GraphingCalculator\KeyGraphFeaturesTemplateSelector.cs" />
<Compile Include="Selectors\KeyGraphFeaturesTemplateSelector.cs" />
<Compile Include="Utils\DelegateCommandUtils.cs" />
<Compile Include="Views\Calculator.xaml.cs">
<DependentUpon>Calculator.xaml</DependentUpon>
@ -235,7 +236,7 @@
<DependentUpon>Settings.xaml</DependentUpon>
</Compile>
<Compile Include="Views\StateTriggers\AspectRatioTrigger.cs" />
<Compile Include="Views\StateTriggers\CalculatorProgrammerDisplayPanel.xaml.cs">
<Compile Include="Views\CalculatorProgrammerDisplayPanel.xaml.cs">
<DependentUpon>CalculatorProgrammerDisplayPanel.xaml</DependentUpon>
</Compile>
<Compile Include="Views\StateTriggers\ControlSizeTrigger.cs" />
@ -773,7 +774,7 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\StateTriggers\CalculatorProgrammerDisplayPanel.xaml">
<Page Include="Views\CalculatorProgrammerDisplayPanel.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>

View File

@ -579,7 +579,7 @@ private static bool CanNavigateModeByShortcut(MUXC.NavigationView navView, MUXC.
, ApplicationViewModel vm, ViewMode toMode)
{
return nvi != null && nvi.IsEnabled && navView.Visibility == Visibility.Visible
&& !vm.IsAlwaysOnTop && NavCategory.IsValidViewMode(toMode);
&& !vm.IsAlwaysOnTop && NavCategoryStates.IsValidViewMode(toMode);
}
private static void NavigateModeByShortcut(bool controlKeyPressed, bool shiftKeyPressed, bool altPressed
@ -602,8 +602,8 @@ private static void NavigateModeByShortcut(bool controlKeyPressed, bool shiftKey
var vm = (navView.DataContext as ApplicationViewModel);
if (null != vm)
{
ViewMode realToMode = toMode.HasValue ? toMode.Value : NavCategory.GetViewModeForVirtualKey(((MyVirtualKey)key));
var nvi = (menuItems[NavCategory.GetFlatIndex(realToMode)] as MUXC.NavigationViewItem);
ViewMode realToMode = toMode.HasValue ? toMode.Value : NavCategoryStates.GetViewModeForVirtualKey(((MyVirtualKey)key));
var nvi = (menuItems[NavCategoryStates.GetFlatIndex(realToMode)] as MUXC.NavigationViewItem);
if (CanNavigateModeByShortcut(navView, nvi, vm, realToMode))
{
vm.Mode = realToMode;

View File

@ -0,0 +1,38 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using CalculatorApp.ViewModel.Common;
using System;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
namespace CalculatorApp.TemplateSelectors
{
internal sealed class NavViewMenuItemTemplateSelector : DataTemplateSelector
{
public DataTemplate CategoryItemTemplate { get; set; }
public DataTemplate CategoryGroupItemTemplate { get; set; }
protected override DataTemplate SelectTemplateCore(object item)
{
if (item is NavCategory)
{
return CategoryItemTemplate;
}
else if (item is NavCategoryGroup)
{
return CategoryGroupItemTemplate;
}
else
{
throw new NotSupportedException($"typeof(item) must be {nameof(NavCategory)} or {nameof(NavCategoryGroup)}.");
}
}
protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
{
return SelectTemplateCore(item);
}
}
}

View File

@ -7,6 +7,8 @@
xmlns:local="using:CalculatorApp"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
xmlns:selectors="using:CalculatorApp.TemplateSelectors"
xmlns:vmcom="using:CalculatorApp.ViewModel.Common"
x:Name="PageRoot"
muxc:BackdropMaterial.ApplyToRootOrPageBackground="True"
Loaded="OnPageLoaded"
@ -25,6 +27,27 @@
<Style x:Key="NavViewItemStyle" TargetType="muxc:NavigationViewItem">
<Setter Property="KeyTipPlacementMode" Value="Right"/>
</Style>
<DataTemplate x:Key="NavViewCategoryItemDataTemplate" x:DataType="vmcom:NavCategory">
<muxc:NavigationViewItem Content="{x:Bind Name}"
Tag="{x:Bind ViewMode}"
AccessKey="{x:Bind AccessKey}"
IsEnabled="{x:Bind IsEnabled, Mode=OneWay}"
Style="{StaticResource NavViewItemStyle}"
AutomationProperties.Name="{x:Bind AutomationName}"
AutomationProperties.AutomationId="{x:Bind AutomationId}">
<muxc:NavigationViewItem.Icon>
<FontIcon FontFamily="{StaticResource CalculatorFontFamily}" Glyph="{x:Bind Glyph}"/>
</muxc:NavigationViewItem.Icon>
</muxc:NavigationViewItem>
</DataTemplate>
<DataTemplate x:Key="NavViewCategoryGroupItemDataTemplate" x:DataType="vmcom:NavCategoryGroup">
<muxc:NavigationViewItemHeader Content="{x:Bind Name}"
AutomationProperties.Name="{x:Bind AutomationName}"
AutomationProperties.HeadingLevel="Level1"/>
</DataTemplate>
<selectors:NavViewMenuItemTemplateSelector x:Key="NavViewMenuItemTemplateSelector"
CategoryItemTemplate="{StaticResource NavViewCategoryItemDataTemplate}"
CategoryGroupItemTemplate="{StaticResource NavViewCategoryGroupItemDataTemplate}"/>
<converters:BooleanToVisibilityNegationConverter x:Key="BooleanToVisibilityNegationConverter"/>
<converters:BooleanNegationConverter x:Key="BooleanNegationConverter"/>
@ -96,7 +119,8 @@
IsSettingsVisible="True"
ItemInvoked="OnNavItemInvoked"
Loaded="OnNavLoaded"
MenuItemsSource="{x:Bind CreateUIElementsForCategories(Model.Categories), Mode=OneWay}"
MenuItemsSource="{x:Bind NavViewCategoriesSource, Mode=OneWay}"
MenuItemTemplateSelector="{StaticResource NavViewMenuItemTemplateSelector}"
OpenPaneLength="{x:Bind NavigationViewOpenPaneLength(Model.IsAlwaysOnTop), Mode=OneWay}"
PaneDisplayMode="LeftMinimal"
PaneClosed="OnNavPaneClosed"

View File

@ -5,10 +5,8 @@
using CalculatorApp.ViewModel.Common.Automation;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.Graphics.Display;
using Windows.Storage;
using Windows.UI.Core;
@ -28,9 +26,21 @@ namespace CalculatorApp
/// </summary>
public sealed partial class MainPage : Page
{
public static readonly DependencyProperty NavViewCategoriesSourceProperty =
DependencyProperty.Register(nameof(NavViewCategoriesSource), typeof(List<object>), typeof(MainPage), new PropertyMetadata(default));
public List<object> NavViewCategoriesSource
{
get { return (List<object>)GetValue(NavViewCategoriesSourceProperty); }
set { SetValue(NavViewCategoriesSourceProperty, value); }
}
public ApplicationViewModel Model => m_model;
public MainPage()
{
m_model = new ViewModel.ApplicationViewModel();
m_model = new ApplicationViewModel();
InitializeNavViewCategoriesSource();
InitializeComponent();
KeyboardShortcutManager.Initialize();
@ -48,11 +58,6 @@ public MainPage()
}
}
public CalculatorApp.ViewModel.ApplicationViewModel Model
{
get => m_model;
}
public void UnregisterEventHandlers()
{
Window.Current.SizeChanged -= WindowSizeChanged;
@ -111,23 +116,6 @@ public void SetHeaderAutomationName()
AutomationProperties.SetName(Header, name);
}
public ObservableCollection<object> CreateUIElementsForCategories(IObservableVector<NavCategoryGroup> categories)
{
var menuCategories = new ObservableCollection<object>();
foreach (var group in categories)
{
menuCategories.Add(CreateNavViewHeaderFromGroup(group));
foreach (var category in group.Categories)
{
menuCategories.Add(CreateNavViewItemFromCategory(category));
}
}
return menuCategories;
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
ViewMode initialMode = ViewMode.Standard;
@ -142,13 +130,53 @@ protected override void OnNavigatedTo(NavigationEventArgs e)
ApplicationDataContainer localSettings = ApplicationData.Current.LocalSettings;
if (localSettings.Values.ContainsKey(ApplicationViewModel.ModePropertyName))
{
initialMode = NavCategory.Deserialize(localSettings.Values[ApplicationViewModel.ModePropertyName]);
initialMode = NavCategoryStates.Deserialize(localSettings.Values[ApplicationViewModel.ModePropertyName]);
}
}
m_model.Initialize(initialMode);
}
private void InitializeNavViewCategoriesSource()
{
NavViewCategoriesSource = ExpandNavViewCategoryGroups(Model.Categories);
Model.Categories.VectorChanged += (sender, args) =>
{
NavViewCategoriesSource.Clear();
NavViewCategoriesSource = ExpandNavViewCategoryGroups(Model.Categories);
};
_ = Window.Current.Dispatcher.RunAsync(CoreDispatcherPriority.Low, () =>
{
var graphCategory = (NavCategory)NavViewCategoriesSource.Find(x =>
{
if(x is NavCategory category)
{
return category.ViewMode == ViewMode.Graphing;
}
else
{
return false;
}
});
graphCategory.IsEnabled = NavCategoryStates.IsViewModeEnabled(ViewMode.Graphing);
});
}
private List<object> ExpandNavViewCategoryGroups(IEnumerable<NavCategoryGroup> groups)
{
var result = new List<object>();
foreach(var group in groups)
{
result.Add(group);
foreach(var category in group.Categories)
{
result.Add(category);
}
}
return result;
}
private void UpdatePopupSize(Windows.UI.Core.WindowSizeChangedEventArgs e)
{
if(PopupContent != null)
@ -243,9 +271,9 @@ private void OnAppPropertyChanged(object sender, PropertyChangedEventArgs e)
private void SelectNavigationItemByModel()
{
var menuItems = ((ObservableCollection<object>)NavView.MenuItemsSource);
var itemCount = ((int)menuItems.Count);
var flatIndex = NavCategory.GetFlatIndex(Model.Mode);
var menuItems = (List<object>)NavView.MenuItemsSource;
var itemCount = menuItems.Count;
var flatIndex = NavCategoryStates.GetFlatIndex(Model.Mode);
if (flatIndex >= 0 && flatIndex < itemCount)
{
@ -261,7 +289,7 @@ private void OnNavLoaded(object sender, RoutedEventArgs e)
}
var acceleratorList = new List<MyVirtualKey>();
NavCategory.GetCategoryAcceleratorKeys(acceleratorList);
NavCategoryStates.GetCategoryAcceleratorKeys(acceleratorList);
foreach (var accelerator in acceleratorList)
{
@ -340,8 +368,7 @@ private void OnNavSelectionChanged(object sender, MUXC.NavigationViewSelectionCh
var item = (e.SelectedItemContainer as MUXC.NavigationViewItem);
if (item != null)
{
var selectedItem = ((NavCategory)item.DataContext);
Model.Mode = selectedItem.Mode;
Model.Mode = (ViewMode)item.Tag;
}
}
@ -361,39 +388,6 @@ private void TitleBarAlwaysOnTopButtonClick(object sender, RoutedEventArgs e)
Model.ToggleAlwaysOnTop((float)bounds.Width, (float)bounds.Height);
}
private MUXC.NavigationViewItemHeader CreateNavViewHeaderFromGroup(NavCategoryGroup group)
{
var header = new MUXC.NavigationViewItemHeader();
header.DataContext = group;
header.Content = group.Name;
AutomationProperties.SetName(header, group.AutomationName);
AutomationProperties.SetHeadingLevel(header, Windows.UI.Xaml.Automation.Peers.AutomationHeadingLevel.Level1);
return header;
}
private MUXC.NavigationViewItem CreateNavViewItemFromCategory(NavCategory category)
{
var item = new MUXC.NavigationViewItem();
item.DataContext = category;
var icon = new FontIcon();
icon.FontFamily = (Windows.UI.Xaml.Media.FontFamily)(App.Current.Resources["CalculatorFontFamily"]);
icon.Glyph = category.Glyph;
item.Icon = icon;
item.Content = category.Name;
item.AccessKey = category.AccessKey;
item.IsEnabled = category.IsEnabled;
item.Style = (Windows.UI.Xaml.Style)(Resources["NavViewItemStyle"]);
AutomationProperties.SetName(item, category.AutomationName);
AutomationProperties.SetAutomationId(item, category.AutomationId);
return item;
}
private void ShowHideControls(ViewMode mode)
{
var isCalcViewMode = NavCategory.IsCalculatorViewMode(mode);
@ -431,7 +425,7 @@ private void UpdateViewState()
// All layout related view states are now handled only inside individual controls (standard, scientific, programmer, date, converter)
if (NavCategory.IsConverterViewMode(m_model.Mode))
{
int modeIndex = NavCategory.GetIndexInGroup(m_model.Mode, CategoryGroupType.Converter);
int modeIndex = NavCategoryStates.GetIndexInGroup(m_model.Mode, CategoryGroupType.Converter);
m_model.ConverterViewModel.CurrentCategory = m_model.ConverterViewModel.Categories[modeIndex];
}
}
@ -598,11 +592,11 @@ private void Settings_BackButtonClick(object sender, RoutedEventArgs e)
CloseSettingsPopup();
}
private CalculatorApp.Calculator m_calculator;
private Calculator m_calculator;
private GraphingCalculator m_graphingCalculator;
private CalculatorApp.UnitConverter m_converter;
private CalculatorApp.DateCalculator m_dateCalculator;
private CalculatorApp.ViewModel.ApplicationViewModel m_model;
private Windows.UI.ViewManagement.AccessibilitySettings m_accessibilitySettings;
private UnitConverter m_converter;
private DateCalculator m_dateCalculator;
private ApplicationViewModel m_model;
private AccessibilitySettings m_accessibilitySettings;
}
}

View File

@ -392,7 +392,7 @@ private void SupplementaryResultsPanelInGrid_SizeChanged(object sender, Windows.
private void OnVisualStateChanged(object sender, Windows.UI.Xaml.VisualStateChangedEventArgs e)
{
var mode = NavCategory.Deserialize(Model.CurrentCategory.GetModelCategoryId());
var mode = NavCategoryStates.Deserialize(Model.CurrentCategory.GetModelCategoryId());
TraceLogger.GetInstance().LogVisualStateChanged(mode, e.NewState.Name, false);
}

View File

@ -382,7 +382,7 @@ TEST_METHOD(Load_Success_LoadedFromWeb)
TEST_CLASS(CurrencyConverterUnitTests)
{
const UCM::Category CURRENCY_CATEGORY = { NavCategory::Serialize(ViewMode::Currency), L"Currency", false /*supportsNegative*/ };
const UCM::Category CURRENCY_CATEGORY = { NavCategoryStates::Serialize(ViewMode::Currency), L"Currency", false /*supportsNegative*/ };
const UCM::Unit GetUnit(const vector<UCM::Unit>& unitList, const wstring& target)
{

View File

@ -735,8 +735,8 @@ TEST_METHOD(MultipleConverterModeCalculationTest)
IObservableVector<Unit ^> ^ unitsList[3];
// viewModels 0 & 1 have same category(Volume) and viewModel 2 has different category(Length)
int volumeIndex = NavCategory::GetIndexInGroup(ViewMode::Volume, CategoryGroupType::Converter);
int lengthIndex = NavCategory::GetIndexInGroup(ViewMode::Length, CategoryGroupType::Converter);
int volumeIndex = NavCategoryStates::GetIndexInGroup(ViewMode::Volume, CategoryGroupType::Converter);
int lengthIndex = NavCategoryStates::GetIndexInGroup(ViewMode::Length, CategoryGroupType::Converter);
viewModels[0]->CurrentCategory = categoryList->GetAt(volumeIndex);
viewModels[1]->CurrentCategory = categoryList->GetAt(volumeIndex);
viewModels[2]->CurrentCategory = categoryList->GetAt(lengthIndex);
@ -814,7 +814,7 @@ TEST_METHOD(TestStandardUnitConverterAndDateViewModels)
dateCalcViewModel->IsAddMode = true;
// Initialize Unit Converter
int volumeCategoryIndex = NavCategory::GetIndexInGroup(ViewMode::Volume, CategoryGroupType::Converter);
int volumeCategoryIndex = NavCategoryStates::GetIndexInGroup(ViewMode::Volume, CategoryGroupType::Converter);
IObservableVector<Category ^> ^ categories = unitConverterViewModel->Categories;
unitConverterViewModel->CurrentCategory = categories->GetAt(volumeCategoryIndex);
unitConverterViewModel->Unit1 = unitConverterViewModel->Units->GetAt(2);

View File

@ -17,136 +17,11 @@ namespace CalculatorUnitTests
TEST_CLASS(NavCategoryUnitTests)
{
public:
TEST_METHOD(Serialize);
TEST_METHOD(Deserialize_AllValid);
TEST_METHOD(Deserialize_AllInvalid);
TEST_METHOD(IsValidViewMode_AllValid);
TEST_METHOD(IsValidViewMode_AllInvalid);
TEST_METHOD(IsCalculatorViewMode);
TEST_METHOD(IsDateCalculatorViewMode);
TEST_METHOD(IsConverterViewMode);
TEST_METHOD(GetFriendlyName);
TEST_METHOD(GetGroupType);
TEST_METHOD(GetIndex);
TEST_METHOD(GetPosition);
TEST_METHOD(GetIndex_GetPosition_Relationship);
TEST_METHOD(GetIndexInGroup);
TEST_METHOD(GetViewModeForVirtualKey);
};
void NavCategoryUnitTests::Serialize()
{
// While values in other tests may change (for example, the order
// of a navigation item might change), these values should NEVER
// change. We are validating the unique ID for each mode, not
// it's position or index.
VERIFY_ARE_EQUAL(0, NavCategory::Serialize(ViewMode::Standard));
VERIFY_ARE_EQUAL(1, NavCategory::Serialize(ViewMode::Scientific));
VERIFY_ARE_EQUAL(2, NavCategory::Serialize(ViewMode::Programmer));
VERIFY_ARE_EQUAL(3, NavCategory::Serialize(ViewMode::Date));
VERIFY_ARE_EQUAL(16, NavCategory::Serialize(ViewMode::Currency));
VERIFY_ARE_EQUAL(4, NavCategory::Serialize(ViewMode::Volume));
VERIFY_ARE_EQUAL(5, NavCategory::Serialize(ViewMode::Length));
VERIFY_ARE_EQUAL(6, NavCategory::Serialize(ViewMode::Weight));
VERIFY_ARE_EQUAL(7, NavCategory::Serialize(ViewMode::Temperature));
VERIFY_ARE_EQUAL(8, NavCategory::Serialize(ViewMode::Energy));
VERIFY_ARE_EQUAL(9, NavCategory::Serialize(ViewMode::Area));
VERIFY_ARE_EQUAL(10, NavCategory::Serialize(ViewMode::Speed));
VERIFY_ARE_EQUAL(11, NavCategory::Serialize(ViewMode::Time));
VERIFY_ARE_EQUAL(12, NavCategory::Serialize(ViewMode::Power));
VERIFY_ARE_EQUAL(13, NavCategory::Serialize(ViewMode::Data));
VERIFY_ARE_EQUAL(14, NavCategory::Serialize(ViewMode::Pressure));
VERIFY_ARE_EQUAL(15, NavCategory::Serialize(ViewMode::Angle));
VERIFY_ARE_EQUAL(-1, NavCategory::Serialize(ViewMode::None));
}
void NavCategoryUnitTests::Deserialize_AllValid()
{
// While values in other tests may change (for example, the order
// of a navigation item might change), these values should NEVER
// change. We are validating the unique ID for each mode, not
// it's position or index.
VERIFY_ARE_EQUAL(ViewMode::Standard, NavCategory::Deserialize(ref new Box<int>(0)));
VERIFY_ARE_EQUAL(ViewMode::Scientific, NavCategory::Deserialize(ref new Box<int>(1)));
VERIFY_ARE_EQUAL(ViewMode::Programmer, NavCategory::Deserialize(ref new Box<int>(2)));
VERIFY_ARE_EQUAL(ViewMode::Date, NavCategory::Deserialize(ref new Box<int>(3)));
VERIFY_ARE_EQUAL(ViewMode::Currency, NavCategory::Deserialize(ref new Box<int>(16)));
VERIFY_ARE_EQUAL(ViewMode::Volume, NavCategory::Deserialize(ref new Box<int>(4)));
VERIFY_ARE_EQUAL(ViewMode::Length, NavCategory::Deserialize(ref new Box<int>(5)));
VERIFY_ARE_EQUAL(ViewMode::Weight, NavCategory::Deserialize(ref new Box<int>(6)));
VERIFY_ARE_EQUAL(ViewMode::Temperature, NavCategory::Deserialize(ref new Box<int>(7)));
VERIFY_ARE_EQUAL(ViewMode::Energy, NavCategory::Deserialize(ref new Box<int>(8)));
VERIFY_ARE_EQUAL(ViewMode::Area, NavCategory::Deserialize(ref new Box<int>(9)));
VERIFY_ARE_EQUAL(ViewMode::Speed, NavCategory::Deserialize(ref new Box<int>(10)));
VERIFY_ARE_EQUAL(ViewMode::Time, NavCategory::Deserialize(ref new Box<int>(11)));
VERIFY_ARE_EQUAL(ViewMode::Power, NavCategory::Deserialize(ref new Box<int>(12)));
VERIFY_ARE_EQUAL(ViewMode::Data, NavCategory::Deserialize(ref new Box<int>(13)));
VERIFY_ARE_EQUAL(ViewMode::Pressure, NavCategory::Deserialize(ref new Box<int>(14)));
VERIFY_ARE_EQUAL(ViewMode::Angle, NavCategory::Deserialize(ref new Box<int>(15)));
}
void NavCategoryUnitTests::Deserialize_AllInvalid()
{
VERIFY_ARE_EQUAL(ViewMode::None, NavCategory::Deserialize(nullptr));
VERIFY_ARE_EQUAL(ViewMode::None, NavCategory::Deserialize(ref new String(L"fail")));
// Boundary testing
VERIFY_ARE_EQUAL(ViewMode::None, NavCategory::Deserialize(ref new Box<int>(-1)));
VERIFY_ARE_EQUAL(ViewMode::None, NavCategory::Deserialize(ref new Box<int>(18)));
}
void NavCategoryUnitTests::IsValidViewMode_AllValid()
{
VERIFY_IS_TRUE(NavCategory::IsValidViewMode(ViewMode::Standard));
VERIFY_IS_TRUE(NavCategory::IsValidViewMode(ViewMode::Scientific));
VERIFY_IS_TRUE(NavCategory::IsValidViewMode(ViewMode::Programmer));
VERIFY_IS_TRUE(NavCategory::IsValidViewMode(ViewMode::Date));
if (Windows::Foundation::Metadata::ApiInformation::IsMethodPresent("Windows.UI.Text.RichEditTextDocument", "GetMath"))
{
VERIFY_IS_TRUE(NavCategory::IsValidViewMode(ViewMode::Graphing));
}
VERIFY_IS_TRUE(NavCategory::IsValidViewMode(ViewMode::Currency));
VERIFY_IS_TRUE(NavCategory::IsValidViewMode(ViewMode::Volume));
VERIFY_IS_TRUE(NavCategory::IsValidViewMode(ViewMode::Length));
VERIFY_IS_TRUE(NavCategory::IsValidViewMode(ViewMode::Weight));
VERIFY_IS_TRUE(NavCategory::IsValidViewMode(ViewMode::Temperature));
VERIFY_IS_TRUE(NavCategory::IsValidViewMode(ViewMode::Energy));
VERIFY_IS_TRUE(NavCategory::IsValidViewMode(ViewMode::Area));
VERIFY_IS_TRUE(NavCategory::IsValidViewMode(ViewMode::Speed));
VERIFY_IS_TRUE(NavCategory::IsValidViewMode(ViewMode::Time));
VERIFY_IS_TRUE(NavCategory::IsValidViewMode(ViewMode::Power));
VERIFY_IS_TRUE(NavCategory::IsValidViewMode(ViewMode::Data));
VERIFY_IS_TRUE(NavCategory::IsValidViewMode(ViewMode::Pressure));
VERIFY_IS_TRUE(NavCategory::IsValidViewMode(ViewMode::Angle));
}
void NavCategoryUnitTests::IsValidViewMode_AllInvalid()
{
VERIFY_IS_FALSE(NavCategory::IsValidViewMode(ViewMode::None));
if (Windows::Foundation::Metadata::ApiInformation::IsMethodPresent("Windows.UI.Text.RichEditTextDocument", "GetMath"))
{
// There are 18 total options so int 18 should be the first invalid
VERIFY_IS_TRUE(NavCategory::IsValidViewMode(static_cast<ViewMode>(17)));
VERIFY_IS_FALSE(NavCategory::IsValidViewMode(static_cast<ViewMode>(18)));
}
else
{
// There are 17 total options when graphing calculator is not present, so int 17 should be the first invalid
VERIFY_IS_TRUE(NavCategory::IsValidViewMode(static_cast<ViewMode>(16)));
VERIFY_IS_FALSE(NavCategory::IsValidViewMode(static_cast<ViewMode>(17)));
}
// Also verify the lower bound
VERIFY_IS_TRUE(NavCategory::IsValidViewMode(static_cast<ViewMode>(0)));
VERIFY_IS_FALSE(NavCategory::IsValidViewMode(static_cast<ViewMode>(-1)));
}
void NavCategoryUnitTests::IsCalculatorViewMode()
{
VERIFY_IS_TRUE(NavCategory::IsCalculatorViewMode(ViewMode::Standard));
@ -154,10 +29,7 @@ namespace CalculatorUnitTests
VERIFY_IS_TRUE(NavCategory::IsCalculatorViewMode(ViewMode::Programmer));
VERIFY_IS_FALSE(NavCategory::IsCalculatorViewMode(ViewMode::Date));
if (Windows::Foundation::Metadata::ApiInformation::IsMethodPresent("Windows.UI.Text.RichEditTextDocument", "GetMath"))
{
VERIFY_IS_FALSE(NavCategory::IsCalculatorViewMode(ViewMode::Graphing));
}
VERIFY_IS_FALSE(NavCategory::IsCalculatorViewMode(ViewMode::Graphing));
VERIFY_IS_FALSE(NavCategory::IsCalculatorViewMode(ViewMode::Currency));
VERIFY_IS_FALSE(NavCategory::IsCalculatorViewMode(ViewMode::Volume));
@ -181,10 +53,7 @@ namespace CalculatorUnitTests
VERIFY_IS_FALSE(NavCategory::IsDateCalculatorViewMode(ViewMode::Programmer));
VERIFY_IS_TRUE(NavCategory::IsDateCalculatorViewMode(ViewMode::Date));
if (Windows::Foundation::Metadata::ApiInformation::IsMethodPresent("Windows.UI.Text.RichEditTextDocument", "GetMath"))
{
VERIFY_IS_FALSE(NavCategory::IsDateCalculatorViewMode(ViewMode::Graphing));
}
VERIFY_IS_FALSE(NavCategory::IsDateCalculatorViewMode(ViewMode::Graphing));
VERIFY_IS_FALSE(NavCategory::IsDateCalculatorViewMode(ViewMode::Currency));
VERIFY_IS_FALSE(NavCategory::IsDateCalculatorViewMode(ViewMode::Volume));
@ -207,10 +76,7 @@ namespace CalculatorUnitTests
VERIFY_IS_FALSE(NavCategory::IsConverterViewMode(ViewMode::Scientific));
VERIFY_IS_FALSE(NavCategory::IsConverterViewMode(ViewMode::Programmer));
VERIFY_IS_FALSE(NavCategory::IsConverterViewMode(ViewMode::Date));
if (Windows::Foundation::Metadata::ApiInformation::IsMethodPresent("Windows.UI.Text.RichEditTextDocument", "GetMath"))
{
VERIFY_IS_FALSE(NavCategory::IsConverterViewMode(ViewMode::Graphing));
}
VERIFY_IS_FALSE(NavCategory::IsConverterViewMode(ViewMode::Graphing));
VERIFY_IS_TRUE(NavCategory::IsConverterViewMode(ViewMode::Currency));
VERIFY_IS_TRUE(NavCategory::IsConverterViewMode(ViewMode::Volume));
@ -227,178 +93,45 @@ namespace CalculatorUnitTests
VERIFY_IS_TRUE(NavCategory::IsConverterViewMode(ViewMode::Angle));
}
void NavCategoryUnitTests::GetFriendlyName()
{
VERIFY_ARE_EQUAL(StringReference(L"Standard"), NavCategory::GetFriendlyName(ViewMode::Standard));
VERIFY_ARE_EQUAL(StringReference(L"Scientific"), NavCategory::GetFriendlyName(ViewMode::Scientific));
VERIFY_ARE_EQUAL(StringReference(L"Programmer"), NavCategory::GetFriendlyName(ViewMode::Programmer));
VERIFY_ARE_EQUAL(StringReference(L"Date"), NavCategory::GetFriendlyName(ViewMode::Date));
if (Windows::Foundation::Metadata::ApiInformation::IsMethodPresent("Windows.UI.Text.RichEditTextDocument", "GetMath"))
{
VERIFY_ARE_EQUAL(StringReference(L"Graphing"), NavCategory::GetFriendlyName(ViewMode::Graphing));
}
VERIFY_ARE_EQUAL(StringReference(L"Currency"), NavCategory::GetFriendlyName(ViewMode::Currency));
VERIFY_ARE_EQUAL(StringReference(L"Volume"), NavCategory::GetFriendlyName(ViewMode::Volume));
VERIFY_ARE_EQUAL(StringReference(L"Length"), NavCategory::GetFriendlyName(ViewMode::Length));
VERIFY_ARE_EQUAL(StringReference(L"Weight and Mass"), NavCategory::GetFriendlyName(ViewMode::Weight));
VERIFY_ARE_EQUAL(StringReference(L"Temperature"), NavCategory::GetFriendlyName(ViewMode::Temperature));
VERIFY_ARE_EQUAL(StringReference(L"Energy"), NavCategory::GetFriendlyName(ViewMode::Energy));
VERIFY_ARE_EQUAL(StringReference(L"Area"), NavCategory::GetFriendlyName(ViewMode::Area));
VERIFY_ARE_EQUAL(StringReference(L"Speed"), NavCategory::GetFriendlyName(ViewMode::Speed));
VERIFY_ARE_EQUAL(StringReference(L"Time"), NavCategory::GetFriendlyName(ViewMode::Time));
VERIFY_ARE_EQUAL(StringReference(L"Power"), NavCategory::GetFriendlyName(ViewMode::Power));
VERIFY_ARE_EQUAL(StringReference(L"Data"), NavCategory::GetFriendlyName(ViewMode::Data));
VERIFY_ARE_EQUAL(StringReference(L"Pressure"), NavCategory::GetFriendlyName(ViewMode::Pressure));
VERIFY_ARE_EQUAL(StringReference(L"Angle"), NavCategory::GetFriendlyName(ViewMode::Angle));
VERIFY_ARE_EQUAL(StringReference(L"None"), NavCategory::GetFriendlyName(ViewMode::None));
}
void NavCategoryUnitTests::GetGroupType()
{
VERIFY_ARE_EQUAL(CategoryGroupType::Calculator, NavCategory::GetGroupType(ViewMode::Standard));
VERIFY_ARE_EQUAL(CategoryGroupType::Calculator, NavCategory::GetGroupType(ViewMode::Scientific));
VERIFY_ARE_EQUAL(CategoryGroupType::Calculator, NavCategory::GetGroupType(ViewMode::Programmer));
VERIFY_ARE_EQUAL(CategoryGroupType::Calculator, NavCategory::GetGroupType(ViewMode::Date));
if (Windows::Foundation::Metadata::ApiInformation::IsMethodPresent("Windows.UI.Text.RichEditTextDocument", "GetMath"))
{
VERIFY_ARE_EQUAL(CategoryGroupType::Calculator, NavCategory::GetGroupType(ViewMode::Graphing));
}
VERIFY_ARE_EQUAL(CategoryGroupType::Converter, NavCategory::GetGroupType(ViewMode::Currency));
VERIFY_ARE_EQUAL(CategoryGroupType::Converter, NavCategory::GetGroupType(ViewMode::Volume));
VERIFY_ARE_EQUAL(CategoryGroupType::Converter, NavCategory::GetGroupType(ViewMode::Length));
VERIFY_ARE_EQUAL(CategoryGroupType::Converter, NavCategory::GetGroupType(ViewMode::Weight));
VERIFY_ARE_EQUAL(CategoryGroupType::Converter, NavCategory::GetGroupType(ViewMode::Temperature));
VERIFY_ARE_EQUAL(CategoryGroupType::Converter, NavCategory::GetGroupType(ViewMode::Energy));
VERIFY_ARE_EQUAL(CategoryGroupType::Converter, NavCategory::GetGroupType(ViewMode::Area));
VERIFY_ARE_EQUAL(CategoryGroupType::Converter, NavCategory::GetGroupType(ViewMode::Speed));
VERIFY_ARE_EQUAL(CategoryGroupType::Converter, NavCategory::GetGroupType(ViewMode::Time));
VERIFY_ARE_EQUAL(CategoryGroupType::Converter, NavCategory::GetGroupType(ViewMode::Power));
VERIFY_ARE_EQUAL(CategoryGroupType::Converter, NavCategory::GetGroupType(ViewMode::Data));
VERIFY_ARE_EQUAL(CategoryGroupType::Converter, NavCategory::GetGroupType(ViewMode::Pressure));
VERIFY_ARE_EQUAL(CategoryGroupType::Converter, NavCategory::GetGroupType(ViewMode::Angle));
}
void NavCategoryUnitTests::GetIndex()
{
// Index is the 0-based ordering of modes
vector<ViewMode> orderedModes;
if (Windows::Foundation::Metadata::ApiInformation::IsMethodPresent("Windows.UI.Text.RichEditTextDocument", "GetMath"))
{
orderedModes = { ViewMode::Standard, ViewMode::Scientific, ViewMode::Graphing, ViewMode::Programmer, ViewMode::Date, ViewMode::Currency,
ViewMode::Volume, ViewMode::Length, ViewMode::Weight, ViewMode::Temperature, ViewMode::Energy, ViewMode::Area,
ViewMode::Speed, ViewMode::Time, ViewMode::Power, ViewMode::Data, ViewMode::Pressure, ViewMode::Angle };
}
else
{
orderedModes = { ViewMode::Standard, ViewMode::Scientific, ViewMode::Programmer, ViewMode::Date, ViewMode::Currency, ViewMode::Volume,
ViewMode::Length, ViewMode::Weight, ViewMode::Temperature, ViewMode::Energy, ViewMode::Area, ViewMode::Speed,
ViewMode::Time, ViewMode::Power, ViewMode::Data, ViewMode::Pressure, ViewMode::Angle };
}
auto orderedModesSize = size(orderedModes);
for (size_t index = 0; index < orderedModesSize; index++)
{
ViewMode mode = orderedModes[index];
VERIFY_ARE_EQUAL(index, (size_t)NavCategory::GetIndex(mode));
}
VERIFY_ARE_EQUAL(-1, NavCategory::GetIndex(ViewMode::None));
}
void NavCategoryUnitTests::GetPosition()
{
// Position is the 1-based ordering of modes
vector<ViewMode> orderedModes;
if (Windows::Foundation::Metadata::ApiInformation::IsMethodPresent("Windows.UI.Text.RichEditTextDocument", "GetMath"))
{
orderedModes = { ViewMode::Standard, ViewMode::Scientific, ViewMode::Graphing, ViewMode::Programmer, ViewMode::Date, ViewMode::Currency,
ViewMode::Volume, ViewMode::Length, ViewMode::Weight, ViewMode::Temperature, ViewMode::Energy, ViewMode::Area,
ViewMode::Speed, ViewMode::Time, ViewMode::Power, ViewMode::Data, ViewMode::Pressure, ViewMode::Angle };
}
else
{
orderedModes = { ViewMode::Standard, ViewMode::Scientific, ViewMode::Programmer, ViewMode::Date, ViewMode::Currency, ViewMode::Volume,
ViewMode::Length, ViewMode::Weight, ViewMode::Temperature, ViewMode::Energy, ViewMode::Area, ViewMode::Speed,
ViewMode::Time, ViewMode::Power, ViewMode::Data, ViewMode::Pressure, ViewMode::Angle };
}
auto orderedModesSize = size(orderedModes);
for (size_t pos = 1; pos <= orderedModesSize; pos++)
{
ViewMode mode = orderedModes[pos - 1];
VERIFY_ARE_EQUAL(pos, (size_t)NavCategory::GetPosition(mode));
}
VERIFY_ARE_EQUAL(-1, NavCategory::GetPosition(ViewMode::None));
}
void NavCategoryUnitTests::GetIndex_GetPosition_Relationship()
{
// Index should be 1 less than Position.
// The other checks verify the order of Index and Position.
// Just verify the relationship here.
VERIFY_ARE_EQUAL(NavCategory::GetIndex(ViewMode::Standard) + 1, NavCategory::GetPosition(ViewMode::Standard));
VERIFY_ARE_EQUAL(NavCategory::GetPosition(ViewMode::Volume) - 1, NavCategory::GetIndex(ViewMode::Volume));
}
void NavCategoryUnitTests::GetIndexInGroup()
{
VERIFY_ARE_EQUAL(0, NavCategory::GetIndexInGroup(ViewMode::Standard, CategoryGroupType::Calculator));
VERIFY_ARE_EQUAL(1, NavCategory::GetIndexInGroup(ViewMode::Scientific, CategoryGroupType::Calculator));
if (Windows::Foundation::Metadata::ApiInformation::IsMethodPresent("Windows.UI.Text.RichEditTextDocument", "GetMath"))
{
VERIFY_ARE_EQUAL(2, NavCategory::GetIndexInGroup(ViewMode::Graphing, CategoryGroupType::Calculator));
VERIFY_ARE_EQUAL(3, NavCategory::GetIndexInGroup(ViewMode::Programmer, CategoryGroupType::Calculator));
VERIFY_ARE_EQUAL(4, NavCategory::GetIndexInGroup(ViewMode::Date, CategoryGroupType::Calculator));
}
else
{
VERIFY_ARE_EQUAL(2, NavCategory::GetIndexInGroup(ViewMode::Programmer, CategoryGroupType::Calculator));
VERIFY_ARE_EQUAL(3, NavCategory::GetIndexInGroup(ViewMode::Date, CategoryGroupType::Calculator));
}
VERIFY_ARE_EQUAL(0, NavCategory::GetIndexInGroup(ViewMode::Currency, CategoryGroupType::Converter));
VERIFY_ARE_EQUAL(1, NavCategory::GetIndexInGroup(ViewMode::Volume, CategoryGroupType::Converter));
VERIFY_ARE_EQUAL(2, NavCategory::GetIndexInGroup(ViewMode::Length, CategoryGroupType::Converter));
VERIFY_ARE_EQUAL(3, NavCategory::GetIndexInGroup(ViewMode::Weight, CategoryGroupType::Converter));
VERIFY_ARE_EQUAL(4, NavCategory::GetIndexInGroup(ViewMode::Temperature, CategoryGroupType::Converter));
VERIFY_ARE_EQUAL(5, NavCategory::GetIndexInGroup(ViewMode::Energy, CategoryGroupType::Converter));
VERIFY_ARE_EQUAL(6, NavCategory::GetIndexInGroup(ViewMode::Area, CategoryGroupType::Converter));
VERIFY_ARE_EQUAL(7, NavCategory::GetIndexInGroup(ViewMode::Speed, CategoryGroupType::Converter));
VERIFY_ARE_EQUAL(8, NavCategory::GetIndexInGroup(ViewMode::Time, CategoryGroupType::Converter));
VERIFY_ARE_EQUAL(9, NavCategory::GetIndexInGroup(ViewMode::Power, CategoryGroupType::Converter));
VERIFY_ARE_EQUAL(10, NavCategory::GetIndexInGroup(ViewMode::Data, CategoryGroupType::Converter));
VERIFY_ARE_EQUAL(11, NavCategory::GetIndexInGroup(ViewMode::Pressure, CategoryGroupType::Converter));
VERIFY_ARE_EQUAL(12, NavCategory::GetIndexInGroup(ViewMode::Angle, CategoryGroupType::Converter));
VERIFY_ARE_EQUAL(-1, NavCategory::GetIndexInGroup(ViewMode::None, CategoryGroupType::Calculator));
VERIFY_ARE_EQUAL(-1, NavCategory::GetIndexInGroup(ViewMode::None, CategoryGroupType::Converter));
}
void NavCategoryUnitTests::GetViewModeForVirtualKey()
{
VERIFY_ARE_EQUAL(ViewMode::Standard, NavCategory::GetViewModeForVirtualKey(MyVirtualKey::Number1));
VERIFY_ARE_EQUAL(ViewMode::Scientific, NavCategory::GetViewModeForVirtualKey(MyVirtualKey::Number2));
if (Windows::Foundation::Metadata::ApiInformation::IsMethodPresent("Windows.UI.Text.RichEditTextDocument", "GetMath"))
{
VERIFY_ARE_EQUAL(ViewMode::Graphing, NavCategory::GetViewModeForVirtualKey(MyVirtualKey::Number3));
VERIFY_ARE_EQUAL(ViewMode::Programmer, NavCategory::GetViewModeForVirtualKey(MyVirtualKey::Number4));
VERIFY_ARE_EQUAL(ViewMode::Date, NavCategory::GetViewModeForVirtualKey(MyVirtualKey::Number5));
}
else
{
VERIFY_ARE_EQUAL(ViewMode::Programmer, NavCategory::GetViewModeForVirtualKey(MyVirtualKey::Number3));
VERIFY_ARE_EQUAL(ViewMode::Date, NavCategory::GetViewModeForVirtualKey(MyVirtualKey::Number4));
}
}
TEST_CLASS(NavCategoryGroupUnitTests)
{
public:
TEST_METHOD(CreateNavCategoryGroup);
TEST_METHOD(CreateNavCategoryGroup)
{
IObservableVector<NavCategoryGroup ^> ^ menuOptions = NavCategoryStates::CreateMenuOptions();
VERIFY_ARE_EQUAL(2, menuOptions->Size);
NavCategoryGroup ^ calculatorGroup = menuOptions->GetAt(0);
VERIFY_ARE_EQUAL(CategoryGroupType::Calculator, calculatorGroup->GroupType);
IObservableVector<NavCategory ^> ^ calculatorCategories = calculatorGroup->Categories;
ValidateNavCategory(calculatorCategories, 0u, ViewMode::Standard);
ValidateNavCategory(calculatorCategories, 1u, ViewMode::Scientific);
ValidateNavCategory(calculatorCategories, 2u, ViewMode::Graphing);
ValidateNavCategory(calculatorCategories, 3u, ViewMode::Programmer);
ValidateNavCategory(calculatorCategories, 4u, ViewMode::Date);
VERIFY_ARE_EQUAL(5, calculatorCategories->Size);
NavCategoryGroup ^ converterGroup = menuOptions->GetAt(1);
VERIFY_ARE_EQUAL(CategoryGroupType::Converter, converterGroup->GroupType);
IObservableVector<NavCategory ^> ^ converterCategories = converterGroup->Categories;
VERIFY_ARE_EQUAL(13, converterCategories->Size);
ValidateNavCategory(converterCategories, 0u, ViewMode::Currency);
ValidateNavCategory(converterCategories, 1u, ViewMode::Volume);
ValidateNavCategory(converterCategories, 2u, ViewMode::Length);
ValidateNavCategory(converterCategories, 3u, ViewMode::Weight);
ValidateNavCategory(converterCategories, 4u, ViewMode::Temperature);
ValidateNavCategory(converterCategories, 5u, ViewMode::Energy);
ValidateNavCategory(converterCategories, 6u, ViewMode::Area);
ValidateNavCategory(converterCategories, 7u, ViewMode::Speed);
ValidateNavCategory(converterCategories, 8u, ViewMode::Time);
ValidateNavCategory(converterCategories, 9u, ViewMode::Power);
ValidateNavCategory(converterCategories, 10u, ViewMode::Data);
ValidateNavCategory(converterCategories, 11u, ViewMode::Pressure);
ValidateNavCategory(converterCategories, 12u, ViewMode::Angle);
}
private:
void ValidateNavCategory(IObservableVector<NavCategory ^> ^ categories, unsigned int index, ViewMode expectedMode)
@ -407,53 +140,240 @@ namespace CalculatorUnitTests
VERIFY_IS_GREATER_THAN(categories->Size, index);
NavCategory ^ category = categories->GetAt(index);
VERIFY_ARE_EQUAL(expectedMode, category->Mode);
VERIFY_ARE_EQUAL(expectedMode, category->ViewMode);
VERIFY_ARE_EQUAL(category->IsEnabled, (expectedMode != ViewMode::Graphing) ? true : false);
}
};
void NavCategoryGroupUnitTests::CreateNavCategoryGroup()
TEST_CLASS(NavCategoryStatesUnitTests)
{
IObservableVector<NavCategoryGroup ^> ^ menuOptions = NavCategoryGroup::CreateMenuOptions();
VERIFY_ARE_EQUAL(2, menuOptions->Size);
NavCategoryGroup ^ calculatorGroup = menuOptions->GetAt(0);
VERIFY_ARE_EQUAL(CategoryGroupType::Calculator, calculatorGroup->GroupType);
IObservableVector<NavCategory ^> ^ calculatorCategories = calculatorGroup->Categories;
ValidateNavCategory(calculatorCategories, 0u, ViewMode::Standard);
ValidateNavCategory(calculatorCategories, 1u, ViewMode::Scientific);
if (Windows::Foundation::Metadata::ApiInformation::IsMethodPresent("Windows.UI.Text.RichEditTextDocument", "GetMath"))
public:
TEST_METHOD(Serialize)
{
ValidateNavCategory(calculatorCategories, 2u, ViewMode::Graphing);
ValidateNavCategory(calculatorCategories, 3u, ViewMode::Programmer);
ValidateNavCategory(calculatorCategories, 4u, ViewMode::Date);
VERIFY_ARE_EQUAL(5, calculatorCategories->Size);
}
else
{
ValidateNavCategory(calculatorCategories, 2u, ViewMode::Programmer);
ValidateNavCategory(calculatorCategories, 3u, ViewMode::Date);
VERIFY_ARE_EQUAL(4, calculatorCategories->Size);
// While values in other tests may change (for example, the order
// of a navigation item might change), these values should NEVER
// change. We are validating the unique ID for each mode, not
// it's position or index.
VERIFY_ARE_EQUAL(0, NavCategoryStates::Serialize(ViewMode::Standard));
VERIFY_ARE_EQUAL(1, NavCategoryStates::Serialize(ViewMode::Scientific));
VERIFY_ARE_EQUAL(2, NavCategoryStates::Serialize(ViewMode::Programmer));
VERIFY_ARE_EQUAL(3, NavCategoryStates::Serialize(ViewMode::Date));
VERIFY_ARE_EQUAL(16, NavCategoryStates::Serialize(ViewMode::Currency));
VERIFY_ARE_EQUAL(4, NavCategoryStates::Serialize(ViewMode::Volume));
VERIFY_ARE_EQUAL(5, NavCategoryStates::Serialize(ViewMode::Length));
VERIFY_ARE_EQUAL(6, NavCategoryStates::Serialize(ViewMode::Weight));
VERIFY_ARE_EQUAL(7, NavCategoryStates::Serialize(ViewMode::Temperature));
VERIFY_ARE_EQUAL(8, NavCategoryStates::Serialize(ViewMode::Energy));
VERIFY_ARE_EQUAL(9, NavCategoryStates::Serialize(ViewMode::Area));
VERIFY_ARE_EQUAL(10, NavCategoryStates::Serialize(ViewMode::Speed));
VERIFY_ARE_EQUAL(11, NavCategoryStates::Serialize(ViewMode::Time));
VERIFY_ARE_EQUAL(12, NavCategoryStates::Serialize(ViewMode::Power));
VERIFY_ARE_EQUAL(13, NavCategoryStates::Serialize(ViewMode::Data));
VERIFY_ARE_EQUAL(14, NavCategoryStates::Serialize(ViewMode::Pressure));
VERIFY_ARE_EQUAL(15, NavCategoryStates::Serialize(ViewMode::Angle));
VERIFY_ARE_EQUAL(-1, NavCategoryStates::Serialize(ViewMode::None));
}
NavCategoryGroup ^ converterGroup = menuOptions->GetAt(1);
VERIFY_ARE_EQUAL(CategoryGroupType::Converter, converterGroup->GroupType);
TEST_METHOD(Deserialize_AllValid)
{
// While values in other tests may change (for example, the order
// of a navigation item might change), these values should NEVER
// change. We are validating the unique ID for each mode, not
// it's position or index.
VERIFY_ARE_EQUAL(ViewMode::Standard, NavCategoryStates::Deserialize(ref new Box<int>(0)));
VERIFY_ARE_EQUAL(ViewMode::Scientific, NavCategoryStates::Deserialize(ref new Box<int>(1)));
VERIFY_ARE_EQUAL(ViewMode::Programmer, NavCategoryStates::Deserialize(ref new Box<int>(2)));
VERIFY_ARE_EQUAL(ViewMode::Date, NavCategoryStates::Deserialize(ref new Box<int>(3)));
VERIFY_ARE_EQUAL(ViewMode::Currency, NavCategoryStates::Deserialize(ref new Box<int>(16)));
VERIFY_ARE_EQUAL(ViewMode::Volume, NavCategoryStates::Deserialize(ref new Box<int>(4)));
VERIFY_ARE_EQUAL(ViewMode::Length, NavCategoryStates::Deserialize(ref new Box<int>(5)));
VERIFY_ARE_EQUAL(ViewMode::Weight, NavCategoryStates::Deserialize(ref new Box<int>(6)));
VERIFY_ARE_EQUAL(ViewMode::Temperature, NavCategoryStates::Deserialize(ref new Box<int>(7)));
VERIFY_ARE_EQUAL(ViewMode::Energy, NavCategoryStates::Deserialize(ref new Box<int>(8)));
VERIFY_ARE_EQUAL(ViewMode::Area, NavCategoryStates::Deserialize(ref new Box<int>(9)));
VERIFY_ARE_EQUAL(ViewMode::Speed, NavCategoryStates::Deserialize(ref new Box<int>(10)));
VERIFY_ARE_EQUAL(ViewMode::Time, NavCategoryStates::Deserialize(ref new Box<int>(11)));
VERIFY_ARE_EQUAL(ViewMode::Power, NavCategoryStates::Deserialize(ref new Box<int>(12)));
VERIFY_ARE_EQUAL(ViewMode::Data, NavCategoryStates::Deserialize(ref new Box<int>(13)));
VERIFY_ARE_EQUAL(ViewMode::Pressure, NavCategoryStates::Deserialize(ref new Box<int>(14)));
VERIFY_ARE_EQUAL(ViewMode::Angle, NavCategoryStates::Deserialize(ref new Box<int>(15)));
}
IObservableVector<NavCategory ^> ^ converterCategories = converterGroup->Categories;
VERIFY_ARE_EQUAL(13, converterCategories->Size);
ValidateNavCategory(converterCategories, 0u, ViewMode::Currency);
ValidateNavCategory(converterCategories, 1u, ViewMode::Volume);
ValidateNavCategory(converterCategories, 2u, ViewMode::Length);
ValidateNavCategory(converterCategories, 3u, ViewMode::Weight);
ValidateNavCategory(converterCategories, 4u, ViewMode::Temperature);
ValidateNavCategory(converterCategories, 5u, ViewMode::Energy);
ValidateNavCategory(converterCategories, 6u, ViewMode::Area);
ValidateNavCategory(converterCategories, 7u, ViewMode::Speed);
ValidateNavCategory(converterCategories, 8u, ViewMode::Time);
ValidateNavCategory(converterCategories, 9u, ViewMode::Power);
ValidateNavCategory(converterCategories, 10u, ViewMode::Data);
ValidateNavCategory(converterCategories, 11u, ViewMode::Pressure);
ValidateNavCategory(converterCategories, 12u, ViewMode::Angle);
}
TEST_METHOD(Deserialize_AllInvalid)
{
VERIFY_ARE_EQUAL(ViewMode::None, NavCategoryStates::Deserialize(nullptr));
VERIFY_ARE_EQUAL(ViewMode::None, NavCategoryStates::Deserialize(ref new String(L"fail")));
// Boundary testing
VERIFY_ARE_EQUAL(ViewMode::None, NavCategoryStates::Deserialize(ref new Box<int>(-1)));
VERIFY_ARE_EQUAL(ViewMode::None, NavCategoryStates::Deserialize(ref new Box<int>(18)));
}
TEST_METHOD(IsValidViewMode_AllValid)
{
VERIFY_IS_TRUE(NavCategoryStates::IsValidViewMode(ViewMode::Standard));
VERIFY_IS_TRUE(NavCategoryStates::IsValidViewMode(ViewMode::Scientific));
VERIFY_IS_TRUE(NavCategoryStates::IsValidViewMode(ViewMode::Programmer));
VERIFY_IS_TRUE(NavCategoryStates::IsValidViewMode(ViewMode::Date));
VERIFY_IS_TRUE(NavCategoryStates::IsValidViewMode(ViewMode::Graphing));
VERIFY_IS_TRUE(NavCategoryStates::IsValidViewMode(ViewMode::Currency));
VERIFY_IS_TRUE(NavCategoryStates::IsValidViewMode(ViewMode::Volume));
VERIFY_IS_TRUE(NavCategoryStates::IsValidViewMode(ViewMode::Length));
VERIFY_IS_TRUE(NavCategoryStates::IsValidViewMode(ViewMode::Weight));
VERIFY_IS_TRUE(NavCategoryStates::IsValidViewMode(ViewMode::Temperature));
VERIFY_IS_TRUE(NavCategoryStates::IsValidViewMode(ViewMode::Energy));
VERIFY_IS_TRUE(NavCategoryStates::IsValidViewMode(ViewMode::Area));
VERIFY_IS_TRUE(NavCategoryStates::IsValidViewMode(ViewMode::Speed));
VERIFY_IS_TRUE(NavCategoryStates::IsValidViewMode(ViewMode::Time));
VERIFY_IS_TRUE(NavCategoryStates::IsValidViewMode(ViewMode::Power));
VERIFY_IS_TRUE(NavCategoryStates::IsValidViewMode(ViewMode::Data));
VERIFY_IS_TRUE(NavCategoryStates::IsValidViewMode(ViewMode::Pressure));
VERIFY_IS_TRUE(NavCategoryStates::IsValidViewMode(ViewMode::Angle));
}
TEST_METHOD(IsValidViewMode_AllInvalid)
{
VERIFY_IS_FALSE(NavCategoryStates::IsValidViewMode(ViewMode::None));
VERIFY_IS_TRUE(NavCategoryStates::IsValidViewMode(static_cast<ViewMode>(17)));
VERIFY_IS_FALSE(NavCategoryStates::IsValidViewMode(static_cast<ViewMode>(18)));
// Also verify the lower bound
VERIFY_IS_TRUE(NavCategoryStates::IsValidViewMode(static_cast<ViewMode>(0)));
VERIFY_IS_FALSE(NavCategoryStates::IsValidViewMode(static_cast<ViewMode>(-1)));
}
TEST_METHOD(GetFriendlyName)
{
VERIFY_ARE_EQUAL(StringReference(L"Standard"), NavCategoryStates::GetFriendlyName(ViewMode::Standard));
VERIFY_ARE_EQUAL(StringReference(L"Scientific"), NavCategoryStates::GetFriendlyName(ViewMode::Scientific));
VERIFY_ARE_EQUAL(StringReference(L"Programmer"), NavCategoryStates::GetFriendlyName(ViewMode::Programmer));
VERIFY_ARE_EQUAL(StringReference(L"Date"), NavCategoryStates::GetFriendlyName(ViewMode::Date));
VERIFY_ARE_EQUAL(StringReference(L"Graphing"), NavCategoryStates::GetFriendlyName(ViewMode::Graphing));
VERIFY_ARE_EQUAL(StringReference(L"Currency"), NavCategoryStates::GetFriendlyName(ViewMode::Currency));
VERIFY_ARE_EQUAL(StringReference(L"Volume"), NavCategoryStates::GetFriendlyName(ViewMode::Volume));
VERIFY_ARE_EQUAL(StringReference(L"Length"), NavCategoryStates::GetFriendlyName(ViewMode::Length));
VERIFY_ARE_EQUAL(StringReference(L"Weight and Mass"), NavCategoryStates::GetFriendlyName(ViewMode::Weight));
VERIFY_ARE_EQUAL(StringReference(L"Temperature"), NavCategoryStates::GetFriendlyName(ViewMode::Temperature));
VERIFY_ARE_EQUAL(StringReference(L"Energy"), NavCategoryStates::GetFriendlyName(ViewMode::Energy));
VERIFY_ARE_EQUAL(StringReference(L"Area"), NavCategoryStates::GetFriendlyName(ViewMode::Area));
VERIFY_ARE_EQUAL(StringReference(L"Speed"), NavCategoryStates::GetFriendlyName(ViewMode::Speed));
VERIFY_ARE_EQUAL(StringReference(L"Time"), NavCategoryStates::GetFriendlyName(ViewMode::Time));
VERIFY_ARE_EQUAL(StringReference(L"Power"), NavCategoryStates::GetFriendlyName(ViewMode::Power));
VERIFY_ARE_EQUAL(StringReference(L"Data"), NavCategoryStates::GetFriendlyName(ViewMode::Data));
VERIFY_ARE_EQUAL(StringReference(L"Pressure"), NavCategoryStates::GetFriendlyName(ViewMode::Pressure));
VERIFY_ARE_EQUAL(StringReference(L"Angle"), NavCategoryStates::GetFriendlyName(ViewMode::Angle));
VERIFY_ARE_EQUAL(StringReference(L"None"), NavCategoryStates::GetFriendlyName(ViewMode::None));
}
TEST_METHOD(GetGroupType)
{
VERIFY_ARE_EQUAL(CategoryGroupType::Calculator, NavCategoryStates::GetGroupType(ViewMode::Standard));
VERIFY_ARE_EQUAL(CategoryGroupType::Calculator, NavCategoryStates::GetGroupType(ViewMode::Scientific));
VERIFY_ARE_EQUAL(CategoryGroupType::Calculator, NavCategoryStates::GetGroupType(ViewMode::Programmer));
VERIFY_ARE_EQUAL(CategoryGroupType::Calculator, NavCategoryStates::GetGroupType(ViewMode::Date));
VERIFY_ARE_EQUAL(CategoryGroupType::Calculator, NavCategoryStates::GetGroupType(ViewMode::Graphing));
VERIFY_ARE_EQUAL(CategoryGroupType::Converter, NavCategoryStates::GetGroupType(ViewMode::Currency));
VERIFY_ARE_EQUAL(CategoryGroupType::Converter, NavCategoryStates::GetGroupType(ViewMode::Volume));
VERIFY_ARE_EQUAL(CategoryGroupType::Converter, NavCategoryStates::GetGroupType(ViewMode::Length));
VERIFY_ARE_EQUAL(CategoryGroupType::Converter, NavCategoryStates::GetGroupType(ViewMode::Weight));
VERIFY_ARE_EQUAL(CategoryGroupType::Converter, NavCategoryStates::GetGroupType(ViewMode::Temperature));
VERIFY_ARE_EQUAL(CategoryGroupType::Converter, NavCategoryStates::GetGroupType(ViewMode::Energy));
VERIFY_ARE_EQUAL(CategoryGroupType::Converter, NavCategoryStates::GetGroupType(ViewMode::Area));
VERIFY_ARE_EQUAL(CategoryGroupType::Converter, NavCategoryStates::GetGroupType(ViewMode::Speed));
VERIFY_ARE_EQUAL(CategoryGroupType::Converter, NavCategoryStates::GetGroupType(ViewMode::Time));
VERIFY_ARE_EQUAL(CategoryGroupType::Converter, NavCategoryStates::GetGroupType(ViewMode::Power));
VERIFY_ARE_EQUAL(CategoryGroupType::Converter, NavCategoryStates::GetGroupType(ViewMode::Data));
VERIFY_ARE_EQUAL(CategoryGroupType::Converter, NavCategoryStates::GetGroupType(ViewMode::Pressure));
VERIFY_ARE_EQUAL(CategoryGroupType::Converter, NavCategoryStates::GetGroupType(ViewMode::Angle));
}
TEST_METHOD(GetIndex)
{
// Index is the 0-based ordering of modes
const auto orderedModesSize = _orderedModes.size();
for (size_t index = 0; index < orderedModesSize; index++)
{
ViewMode mode = _orderedModes[index];
VERIFY_ARE_EQUAL(index, (size_t)NavCategoryStates::GetIndex(mode));
}
VERIFY_ARE_EQUAL(-1, NavCategoryStates::GetIndex(ViewMode::None));
}
TEST_METHOD(GetPosition)
{
// Position is the 1-based ordering of modes
const auto orderedModesSize = _orderedModes.size();
for (size_t pos = 1; pos <= orderedModesSize; pos++)
{
ViewMode mode = _orderedModes[pos - 1];
VERIFY_ARE_EQUAL(pos, (size_t)NavCategoryStates::GetPosition(mode));
}
VERIFY_ARE_EQUAL(-1, NavCategoryStates::GetPosition(ViewMode::None));
}
TEST_METHOD(GetIndex_GetPosition_Relationship)
{
// Index should be 1 less than Position.
// The other checks verify the order of Index and Position.
// Just verify the relationship here.
VERIFY_ARE_EQUAL(NavCategoryStates::GetIndex(ViewMode::Standard) + 1, NavCategoryStates::GetPosition(ViewMode::Standard));
VERIFY_ARE_EQUAL(NavCategoryStates::GetPosition(ViewMode::Volume) - 1, NavCategoryStates::GetIndex(ViewMode::Volume));
}
TEST_METHOD(GetIndexInGroup)
{
VERIFY_ARE_EQUAL(0, NavCategoryStates::GetIndexInGroup(ViewMode::Standard, CategoryGroupType::Calculator));
VERIFY_ARE_EQUAL(1, NavCategoryStates::GetIndexInGroup(ViewMode::Scientific, CategoryGroupType::Calculator));
VERIFY_ARE_EQUAL(2, NavCategoryStates::GetIndexInGroup(ViewMode::Graphing, CategoryGroupType::Calculator));
VERIFY_ARE_EQUAL(3, NavCategoryStates::GetIndexInGroup(ViewMode::Programmer, CategoryGroupType::Calculator));
VERIFY_ARE_EQUAL(4, NavCategoryStates::GetIndexInGroup(ViewMode::Date, CategoryGroupType::Calculator));
VERIFY_ARE_EQUAL(0, NavCategoryStates::GetIndexInGroup(ViewMode::Currency, CategoryGroupType::Converter));
VERIFY_ARE_EQUAL(1, NavCategoryStates::GetIndexInGroup(ViewMode::Volume, CategoryGroupType::Converter));
VERIFY_ARE_EQUAL(2, NavCategoryStates::GetIndexInGroup(ViewMode::Length, CategoryGroupType::Converter));
VERIFY_ARE_EQUAL(3, NavCategoryStates::GetIndexInGroup(ViewMode::Weight, CategoryGroupType::Converter));
VERIFY_ARE_EQUAL(4, NavCategoryStates::GetIndexInGroup(ViewMode::Temperature, CategoryGroupType::Converter));
VERIFY_ARE_EQUAL(5, NavCategoryStates::GetIndexInGroup(ViewMode::Energy, CategoryGroupType::Converter));
VERIFY_ARE_EQUAL(6, NavCategoryStates::GetIndexInGroup(ViewMode::Area, CategoryGroupType::Converter));
VERIFY_ARE_EQUAL(7, NavCategoryStates::GetIndexInGroup(ViewMode::Speed, CategoryGroupType::Converter));
VERIFY_ARE_EQUAL(8, NavCategoryStates::GetIndexInGroup(ViewMode::Time, CategoryGroupType::Converter));
VERIFY_ARE_EQUAL(9, NavCategoryStates::GetIndexInGroup(ViewMode::Power, CategoryGroupType::Converter));
VERIFY_ARE_EQUAL(10, NavCategoryStates::GetIndexInGroup(ViewMode::Data, CategoryGroupType::Converter));
VERIFY_ARE_EQUAL(11, NavCategoryStates::GetIndexInGroup(ViewMode::Pressure, CategoryGroupType::Converter));
VERIFY_ARE_EQUAL(12, NavCategoryStates::GetIndexInGroup(ViewMode::Angle, CategoryGroupType::Converter));
VERIFY_ARE_EQUAL(-1, NavCategoryStates::GetIndexInGroup(ViewMode::None, CategoryGroupType::Calculator));
VERIFY_ARE_EQUAL(-1, NavCategoryStates::GetIndexInGroup(ViewMode::None, CategoryGroupType::Converter));
}
TEST_METHOD(GetViewModeForVirtualKey)
{
VERIFY_ARE_EQUAL(ViewMode::Standard, NavCategoryStates::GetViewModeForVirtualKey(MyVirtualKey::Number1));
VERIFY_ARE_EQUAL(ViewMode::Scientific, NavCategoryStates::GetViewModeForVirtualKey(MyVirtualKey::Number2));
VERIFY_ARE_EQUAL(ViewMode::Graphing, NavCategoryStates::GetViewModeForVirtualKey(MyVirtualKey::Number3));
VERIFY_ARE_EQUAL(ViewMode::Programmer, NavCategoryStates::GetViewModeForVirtualKey(MyVirtualKey::Number4));
VERIFY_ARE_EQUAL(ViewMode::Date, NavCategoryStates::GetViewModeForVirtualKey(MyVirtualKey::Number5));
}
TEST_METHOD(IsViewModeEnabled_ShouldBeTrue_ExceptGraphingMode)
{
for (const auto& mode : _orderedModes)
{
if (mode != ViewMode::Graphing)
{
VERIFY_IS_TRUE(NavCategoryStates::IsViewModeEnabled(mode));
}
}
}
private:
const static inline std::vector<ViewMode> _orderedModes {
ViewMode::Standard, ViewMode::Scientific, ViewMode::Graphing, ViewMode::Programmer, ViewMode::Date, ViewMode::Currency,
ViewMode::Volume, ViewMode::Length, ViewMode::Weight, ViewMode::Temperature, ViewMode::Energy, ViewMode::Area,
ViewMode::Speed, ViewMode::Time, ViewMode::Power, ViewMode::Data, ViewMode::Pressure, ViewMode::Angle };
};
}