mirror of
https://github.com/Microsoft/calculator.git
synced 2025-07-11 15:56:01 -07:00
Improve the Recall support (#2245)
* stash changes * stash changes * pass build * set snapshot * stash changes * update launch utils * stash changes * stash changes * renaming * DeflateUtils * stash changes * deserialization * restore session * connect ui * handle errors * rename CalcManagerHistoryToken * handle optional props * fix optional props * ensure error state * resolve a comment * resolve a comment
This commit is contained in:
parent
9d7d3a6b79
commit
80015d227f
19 changed files with 998 additions and 676 deletions
|
@ -37,446 +37,6 @@ namespace
|
||||||
{
|
{
|
||||||
StringReference CategoriesPropertyName(L"Categories");
|
StringReference CategoriesPropertyName(L"Categories");
|
||||||
StringReference ClearMemoryVisibilityPropertyName(L"ClearMemoryVisibility");
|
StringReference ClearMemoryVisibilityPropertyName(L"ClearMemoryVisibility");
|
||||||
|
|
||||||
struct SnapshotHelper
|
|
||||||
{
|
|
||||||
static constexpr int SnapshotVersion = 0;
|
|
||||||
|
|
||||||
static Windows::Data::Json::JsonObject ^ SaveSnapshotToJson(const ApplicationSnapshot& value)
|
|
||||||
{
|
|
||||||
auto jsonObject = ref new Windows::Data::Json::JsonObject();
|
|
||||||
jsonObject->SetNamedValue(L"SnapshotVersion", Windows::Data::Json::JsonValue::CreateNumberValue(value.SnapshotVersion));
|
|
||||||
jsonObject->SetNamedValue(L"Mode", Windows::Data::Json::JsonValue::CreateNumberValue(value.Mode));
|
|
||||||
if (value.StandardCalc.has_value())
|
|
||||||
{
|
|
||||||
jsonObject->SetNamedValue(L"StandardCalculatorSnapshot", SaveSnapshotToJson(*value.StandardCalc));
|
|
||||||
}
|
|
||||||
return jsonObject;
|
|
||||||
}
|
|
||||||
|
|
||||||
static Windows::Data::Json::JsonObject ^ SaveSnapshotToJson(const StandardCalculatorSnapshot& value)
|
|
||||||
{
|
|
||||||
auto jsonObject = ref new Windows::Data::Json::JsonObject();
|
|
||||||
jsonObject->SetNamedValue(L"CalculatorManagerSnapshot", SaveSnapshotToJson(value.CalcManager));
|
|
||||||
jsonObject->SetNamedValue(L"PrimaryDisplay", SaveSnapshotToJson(value.PrimaryDisplay));
|
|
||||||
if (value.ExpressionDisplay.has_value())
|
|
||||||
{
|
|
||||||
jsonObject->SetNamedValue(L"ExpressionDisplay", SaveSnapshotToJson(*value.ExpressionDisplay));
|
|
||||||
}
|
|
||||||
auto commandsJsonArray = ref new Windows::Data::Json::JsonArray();
|
|
||||||
for (const auto& command : value.DisplayCommands)
|
|
||||||
{
|
|
||||||
commandsJsonArray->Append(SaveSnapshotToJson(command));
|
|
||||||
}
|
|
||||||
jsonObject->SetNamedValue(L"DisplayCommands", commandsJsonArray);
|
|
||||||
return jsonObject;
|
|
||||||
}
|
|
||||||
|
|
||||||
static Windows::Data::Json::JsonObject ^ SaveSnapshotToJson(const PrimaryDisplaySnapshot& value)
|
|
||||||
{
|
|
||||||
auto jsonObject = ref new Windows::Data::Json::JsonObject();
|
|
||||||
jsonObject->SetNamedValue(L"DisplayValue", Windows::Data::Json::JsonValue::CreateStringValue(value.DisplayValue));
|
|
||||||
jsonObject->SetNamedValue(L"IsError", Windows::Data::Json::JsonValue::CreateBooleanValue(value.IsError));
|
|
||||||
return jsonObject;
|
|
||||||
}
|
|
||||||
|
|
||||||
static Windows::Data::Json::JsonObject ^ SaveSnapshotToJson(const ExpressionDisplaySnapshot& value)
|
|
||||||
{
|
|
||||||
auto jsonObject = ref new Windows::Data::Json::JsonObject();
|
|
||||||
auto tokensJsonArray = ref new Windows::Data::Json::JsonArray();
|
|
||||||
for (const auto& token : value.Tokens)
|
|
||||||
{
|
|
||||||
auto tokenJsonArray = ref new Windows::Data::Json::JsonArray();
|
|
||||||
tokenJsonArray->Append(Windows::Data::Json::JsonValue::CreateStringValue(ref new Platform::String(token.first.c_str())));
|
|
||||||
tokenJsonArray->Append(Windows::Data::Json::JsonValue::CreateNumberValue(token.second));
|
|
||||||
tokensJsonArray->Append(tokenJsonArray);
|
|
||||||
}
|
|
||||||
jsonObject->SetNamedValue(L"Tokens", tokensJsonArray);
|
|
||||||
|
|
||||||
auto commandsJsonArray = ref new Windows::Data::Json::JsonArray();
|
|
||||||
for (const auto& command : value.Commands)
|
|
||||||
{
|
|
||||||
commandsJsonArray->Append(SaveSnapshotToJson(command));
|
|
||||||
}
|
|
||||||
jsonObject->SetNamedValue(L"Commands", commandsJsonArray);
|
|
||||||
|
|
||||||
return jsonObject;
|
|
||||||
}
|
|
||||||
|
|
||||||
static Windows::Data::Json::JsonObject ^ SaveSnapshotToJson(const CalculatorManagerSnapshot& value)
|
|
||||||
{
|
|
||||||
auto jsonObject = ref new Windows::Data::Json::JsonObject();
|
|
||||||
if (value.HistoryItems.has_value())
|
|
||||||
{
|
|
||||||
auto historyJsonArray = ref new Windows::Data::Json::JsonArray();
|
|
||||||
for (const auto& item : *value.HistoryItems)
|
|
||||||
{
|
|
||||||
historyJsonArray->Append(SaveSnapshotToJson(*item));
|
|
||||||
}
|
|
||||||
jsonObject->SetNamedValue(L"HistoryItems", historyJsonArray);
|
|
||||||
}
|
|
||||||
return jsonObject;
|
|
||||||
}
|
|
||||||
|
|
||||||
static Windows::Data::Json::JsonObject ^ SaveSnapshotToJson(const CalculationManager::HISTORYITEM& value)
|
|
||||||
{
|
|
||||||
auto jsonObject = ref new Windows::Data::Json::JsonObject();
|
|
||||||
jsonObject->SetNamedValue(L"Expression", Windows::Data::Json::JsonValue::CreateStringValue(ref new Platform::String(value.historyItemVector.expression.c_str())));
|
|
||||||
jsonObject->SetNamedValue(L"Result", Windows::Data::Json::JsonValue::CreateStringValue(ref new Platform::String(value.historyItemVector.result.c_str())));
|
|
||||||
|
|
||||||
auto tokensJsonArray = ref new Windows::Data::Json::JsonArray();
|
|
||||||
for (const auto& token : *value.historyItemVector.spTokens)
|
|
||||||
{
|
|
||||||
auto tokenJsonArray = ref new Windows::Data::Json::JsonArray();
|
|
||||||
tokenJsonArray->Append(Windows::Data::Json::JsonValue::CreateStringValue(ref new Platform::String(token.first.c_str())));
|
|
||||||
tokenJsonArray->Append(Windows::Data::Json::JsonValue::CreateNumberValue(token.second));
|
|
||||||
tokensJsonArray->Append(tokenJsonArray);
|
|
||||||
}
|
|
||||||
jsonObject->SetNamedValue(L"Tokens", tokensJsonArray);
|
|
||||||
|
|
||||||
auto commandsJsonArray = ref new Windows::Data::Json::JsonArray();
|
|
||||||
for (const auto& command : *value.historyItemVector.spCommands)
|
|
||||||
{
|
|
||||||
commandsJsonArray->Append(SaveSnapshotToJson(command));
|
|
||||||
}
|
|
||||||
jsonObject->SetNamedValue(L"Commands", commandsJsonArray);
|
|
||||||
|
|
||||||
return jsonObject;
|
|
||||||
}
|
|
||||||
|
|
||||||
static Windows::Data::Json::JsonObject ^ SaveSnapshotToJson(const std::shared_ptr<IExpressionCommand>& value)
|
|
||||||
{
|
|
||||||
auto jsonObject = ref new Windows::Data::Json::JsonObject();
|
|
||||||
auto opndCommand = dynamic_cast<COpndCommand*>(value.get());
|
|
||||||
if (opndCommand != nullptr)
|
|
||||||
{
|
|
||||||
jsonObject = SaveSnapshotToJson(*opndCommand);
|
|
||||||
}
|
|
||||||
auto unaryCommand = dynamic_cast<CUnaryCommand*>(value.get());
|
|
||||||
if (unaryCommand != nullptr)
|
|
||||||
{
|
|
||||||
jsonObject = SaveSnapshotToJson(*unaryCommand);
|
|
||||||
}
|
|
||||||
auto binaryCommand = dynamic_cast<CBinaryCommand*>(value.get());
|
|
||||||
if (binaryCommand != nullptr)
|
|
||||||
{
|
|
||||||
jsonObject = SaveSnapshotToJson(*binaryCommand);
|
|
||||||
}
|
|
||||||
auto parenthesesCommand = dynamic_cast<CParentheses*>(value.get());
|
|
||||||
if (parenthesesCommand != nullptr)
|
|
||||||
{
|
|
||||||
jsonObject = SaveSnapshotToJson(*parenthesesCommand);
|
|
||||||
}
|
|
||||||
return jsonObject;
|
|
||||||
}
|
|
||||||
|
|
||||||
static Windows::Data::Json::JsonObject ^ SaveSnapshotToJson(const COpndCommand& value)
|
|
||||||
{
|
|
||||||
auto jsonObject = ref new Windows::Data::Json::JsonObject();
|
|
||||||
jsonObject->SetNamedValue(L"CommandType", Windows::Data::Json::JsonValue::CreateNumberValue(static_cast<double>(value.GetCommandType())));
|
|
||||||
jsonObject->SetNamedValue(L"IsNegative", Windows::Data::Json::JsonValue::CreateBooleanValue(value.IsNegative()));
|
|
||||||
jsonObject->SetNamedValue(L"IsDecimalPresent", Windows::Data::Json::JsonValue::CreateBooleanValue(value.IsDecimalPresent()));
|
|
||||||
jsonObject->SetNamedValue(L"IsSciFmt", Windows::Data::Json::JsonValue::CreateBooleanValue(value.IsSciFmt()));
|
|
||||||
auto commandsJsonArray = ref new Windows::Data::Json::JsonArray();
|
|
||||||
for (const auto& command : *value.GetCommands())
|
|
||||||
{
|
|
||||||
commandsJsonArray->Append(Windows::Data::Json::JsonValue::CreateNumberValue(command));
|
|
||||||
}
|
|
||||||
jsonObject->SetNamedValue(L"Commands", commandsJsonArray);
|
|
||||||
return jsonObject;
|
|
||||||
}
|
|
||||||
|
|
||||||
static Windows::Data::Json::JsonObject ^ SaveSnapshotToJson(const CUnaryCommand& value)
|
|
||||||
{
|
|
||||||
auto jsonObject = ref new Windows::Data::Json::JsonObject();
|
|
||||||
jsonObject->SetNamedValue(L"CommandType", Windows::Data::Json::JsonValue::CreateNumberValue(static_cast<double>(value.GetCommandType())));
|
|
||||||
auto commandsJsonArray = ref new Windows::Data::Json::JsonArray();
|
|
||||||
for (const auto& command : *value.GetCommands())
|
|
||||||
{
|
|
||||||
commandsJsonArray->Append(Windows::Data::Json::JsonValue::CreateNumberValue(command));
|
|
||||||
}
|
|
||||||
jsonObject->SetNamedValue(L"Commands", commandsJsonArray);
|
|
||||||
return jsonObject;
|
|
||||||
}
|
|
||||||
|
|
||||||
static Windows::Data::Json::JsonObject ^ SaveSnapshotToJson(const CBinaryCommand& value)
|
|
||||||
{
|
|
||||||
auto jsonObject = ref new Windows::Data::Json::JsonObject();
|
|
||||||
jsonObject->SetNamedValue(L"CommandType", Windows::Data::Json::JsonValue::CreateNumberValue(static_cast<double>(value.GetCommandType())));
|
|
||||||
jsonObject->SetNamedValue(L"Command", Windows::Data::Json::JsonValue::CreateNumberValue(value.GetCommand()));
|
|
||||||
return jsonObject;
|
|
||||||
}
|
|
||||||
|
|
||||||
static Windows::Data::Json::JsonObject ^ SaveSnapshotToJson(const CParentheses& value)
|
|
||||||
{
|
|
||||||
auto jsonObject = ref new Windows::Data::Json::JsonObject();
|
|
||||||
jsonObject->SetNamedValue(L"CommandType", Windows::Data::Json::JsonValue::CreateNumberValue(static_cast<double>(value.GetCommandType())));
|
|
||||||
jsonObject->SetNamedValue(L"Command", Windows::Data::Json::JsonValue::CreateNumberValue(value.GetCommand()));
|
|
||||||
return jsonObject;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void RestoreJsonToSnapshot(Windows::Data::Json::JsonObject ^ jsonObject, std::optional<ApplicationSnapshot>& value)
|
|
||||||
{
|
|
||||||
ApplicationSnapshot applicationSnapshot;
|
|
||||||
applicationSnapshot.SnapshotVersion = static_cast<int>(jsonObject->GetNamedNumber(L"SnapshotVersion"));
|
|
||||||
if (applicationSnapshot.SnapshotVersion > SnapshotVersion)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
applicationSnapshot.Mode = static_cast<int>(jsonObject->GetNamedNumber(L"Mode"));
|
|
||||||
if (jsonObject->HasKey(L"StandardCalculatorSnapshot"))
|
|
||||||
{
|
|
||||||
std::optional<StandardCalculatorSnapshot> standardCalculatorSnapshot;
|
|
||||||
RestoreJsonToSnapshot(jsonObject->GetNamedObject(L"StandardCalculatorSnapshot"), standardCalculatorSnapshot);
|
|
||||||
if (standardCalculatorSnapshot.has_value())
|
|
||||||
{
|
|
||||||
applicationSnapshot.StandardCalc = std::move(*standardCalculatorSnapshot);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
value = std::move(applicationSnapshot);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void RestoreJsonToSnapshot(Windows::Data::Json::JsonObject ^ jsonObject, std::optional<StandardCalculatorSnapshot>& value)
|
|
||||||
{
|
|
||||||
StandardCalculatorSnapshot standardCalculatorSnapshot;
|
|
||||||
std::optional<CalculatorManagerSnapshot> calcManagerSnapshot;
|
|
||||||
RestoreJsonToSnapshot(jsonObject->GetNamedObject(L"CalculatorManagerSnapshot"), calcManagerSnapshot);
|
|
||||||
if (calcManagerSnapshot.has_value())
|
|
||||||
{
|
|
||||||
standardCalculatorSnapshot.CalcManager = std::move(*calcManagerSnapshot);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
std::optional<PrimaryDisplaySnapshot> primaryDisplaySnapshot;
|
|
||||||
RestoreJsonToSnapshot(jsonObject->GetNamedObject(L"PrimaryDisplay"), primaryDisplaySnapshot);
|
|
||||||
if (primaryDisplaySnapshot.has_value())
|
|
||||||
{
|
|
||||||
standardCalculatorSnapshot.PrimaryDisplay = std::move(*primaryDisplaySnapshot);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (jsonObject->HasKey(L"ExpressionDisplay"))
|
|
||||||
{
|
|
||||||
std::optional<ExpressionDisplaySnapshot> expressionDisplaySnapshot;
|
|
||||||
RestoreJsonToSnapshot(jsonObject->GetNamedObject(L"ExpressionDisplay"), expressionDisplaySnapshot);
|
|
||||||
if (expressionDisplaySnapshot.has_value())
|
|
||||||
{
|
|
||||||
standardCalculatorSnapshot.ExpressionDisplay = std::move(*expressionDisplaySnapshot);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
standardCalculatorSnapshot.DisplayCommands = RestoreExpressionCommandsFromJsonArray(jsonObject->GetNamedArray(L"DisplayCommands"));
|
|
||||||
value = std::move(standardCalculatorSnapshot);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void RestoreJsonToSnapshot(Windows::Data::Json::JsonObject ^ jsonObject, std::optional<PrimaryDisplaySnapshot>& value)
|
|
||||||
{
|
|
||||||
value = PrimaryDisplaySnapshot{ jsonObject->GetNamedString(L"DisplayValue"), jsonObject->GetNamedBoolean(L"IsError") };
|
|
||||||
}
|
|
||||||
|
|
||||||
static void RestoreJsonToSnapshot(Windows::Data::Json::JsonObject ^ jsonObject, std::optional<ExpressionDisplaySnapshot>& value)
|
|
||||||
{
|
|
||||||
ExpressionDisplaySnapshot expressionDisplaySnapshot;
|
|
||||||
expressionDisplaySnapshot.Tokens = RestoreExpressionTokensFromJsonArray(jsonObject->GetNamedArray(L"Tokens"));
|
|
||||||
if (expressionDisplaySnapshot.Tokens.empty())
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
expressionDisplaySnapshot.Commands = RestoreExpressionCommandsFromJsonArray(jsonObject->GetNamedArray(L"Commands"));
|
|
||||||
if (expressionDisplaySnapshot.Commands.empty())
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
value = std::move(expressionDisplaySnapshot);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void RestoreJsonToSnapshot(Windows::Data::Json::JsonObject ^ jsonObject, std::optional<CalculatorManagerSnapshot>& value)
|
|
||||||
{
|
|
||||||
CalculatorManagerSnapshot calcManagerSnapshot;
|
|
||||||
if (jsonObject->HasKey(L"HistoryItems"))
|
|
||||||
{
|
|
||||||
std::vector<std::shared_ptr<CalculationManager::HISTORYITEM>> historyItems;
|
|
||||||
auto historyJsonArray = jsonObject->GetNamedArray(L"HistoryItems");
|
|
||||||
for (uint32_t i = 0; i < historyJsonArray->Size; ++i)
|
|
||||||
{
|
|
||||||
std::optional<CalculationManager::HISTORYITEM> historyItem;
|
|
||||||
RestoreJsonToSnapshot(historyJsonArray->GetObjectAt(i), historyItem);
|
|
||||||
if (historyItem.has_value())
|
|
||||||
{
|
|
||||||
historyItems.push_back(std::make_shared<CalculationManager::HISTORYITEM>(*historyItem));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
calcManagerSnapshot.HistoryItems = std::move(historyItems);
|
|
||||||
}
|
|
||||||
value = std::move(calcManagerSnapshot);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void RestoreJsonToSnapshot(Windows::Data::Json::JsonObject ^ jsonObject, std::optional<CalculationManager::HISTORYITEM>& value)
|
|
||||||
{
|
|
||||||
CalculationManager::HISTORYITEM historyItem;
|
|
||||||
historyItem.historyItemVector.expression = std::wstring(jsonObject->GetNamedString(L"Expression")->Data());
|
|
||||||
historyItem.historyItemVector.result = std::wstring(jsonObject->GetNamedString(L"Result")->Data());
|
|
||||||
historyItem.historyItemVector.spTokens =
|
|
||||||
std::make_shared<std::vector<std::pair<std::wstring, int>>>(RestoreExpressionTokensFromJsonArray(jsonObject->GetNamedArray(L"Tokens")));
|
|
||||||
if (historyItem.historyItemVector.spTokens->empty())
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
historyItem.historyItemVector.spCommands = std::make_shared<std::vector<std::shared_ptr<IExpressionCommand>>>(
|
|
||||||
RestoreExpressionCommandsFromJsonArray(jsonObject->GetNamedArray(L"Commands")));
|
|
||||||
if (historyItem.historyItemVector.spCommands->empty())
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
value = std::move(historyItem);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void RestoreJsonToSnapshot(Windows::Data::Json::JsonObject ^ jsonObject, std::optional<std::shared_ptr<IExpressionCommand>>& value)
|
|
||||||
{
|
|
||||||
auto commandType = static_cast<CalculationManager::CommandType>(jsonObject->GetNamedNumber(L"CommandType"));
|
|
||||||
switch (commandType)
|
|
||||||
{
|
|
||||||
case CalculationManager::CommandType::OperandCommand:
|
|
||||||
{
|
|
||||||
std::optional<COpndCommand> opndCommand;
|
|
||||||
RestoreJsonToSnapshot(jsonObject, opndCommand);
|
|
||||||
if (opndCommand.has_value())
|
|
||||||
{
|
|
||||||
value = std::make_shared<COpndCommand>(*opndCommand);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case CalculationManager::CommandType::UnaryCommand:
|
|
||||||
{
|
|
||||||
std::optional<CUnaryCommand> unaryCommand;
|
|
||||||
RestoreJsonToSnapshot(jsonObject, unaryCommand);
|
|
||||||
if (unaryCommand.has_value())
|
|
||||||
{
|
|
||||||
value = std::make_shared<CUnaryCommand>(*unaryCommand);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case CalculationManager::CommandType::BinaryCommand:
|
|
||||||
{
|
|
||||||
std::optional<CBinaryCommand> binaryCommand;
|
|
||||||
RestoreJsonToSnapshot(jsonObject, binaryCommand);
|
|
||||||
if (binaryCommand.has_value())
|
|
||||||
{
|
|
||||||
value = std::make_shared<CBinaryCommand>(*binaryCommand);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case CalculationManager::CommandType::Parentheses:
|
|
||||||
{
|
|
||||||
std::optional<CParentheses> parenthesesCommand;
|
|
||||||
RestoreJsonToSnapshot(jsonObject, parenthesesCommand);
|
|
||||||
if (parenthesesCommand.has_value())
|
|
||||||
{
|
|
||||||
value = std::make_shared<CParentheses>(*parenthesesCommand);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
throw std::logic_error{ "c8cba597-dfec-447a-bd1c-e78a9ffaad95" };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void RestoreJsonToSnapshot(Windows::Data::Json::JsonObject ^ jsonObject, std::optional<COpndCommand>& value)
|
|
||||||
{
|
|
||||||
auto isNegative = jsonObject->GetNamedBoolean(L"IsNegative");
|
|
||||||
auto isDecimalPresent = jsonObject->GetNamedBoolean(L"IsDecimalPresent");
|
|
||||||
auto isSciFmt = jsonObject->GetNamedBoolean(L"IsSciFmt");
|
|
||||||
std::vector<int> commands;
|
|
||||||
auto commandsJsonArray = jsonObject->GetNamedArray(L"Commands");
|
|
||||||
for (uint32_t i = 0; i < commandsJsonArray->Size; ++i)
|
|
||||||
{
|
|
||||||
commands.push_back(static_cast<int>(commandsJsonArray->GetNumberAt(i)));
|
|
||||||
}
|
|
||||||
value = COpndCommand(std::make_shared<std::vector<int>>(std::move(commands)), isNegative, isDecimalPresent, isSciFmt);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void RestoreJsonToSnapshot(Windows::Data::Json::JsonObject ^ jsonObject, std::optional<CUnaryCommand>& value)
|
|
||||||
{
|
|
||||||
std::vector<int> commands;
|
|
||||||
auto commandsJsonArray = jsonObject->GetNamedArray(L"Commands");
|
|
||||||
if (commandsJsonArray->Size == 1)
|
|
||||||
{
|
|
||||||
value = CUnaryCommand(static_cast<int>(commandsJsonArray->GetNumberAt(0)));
|
|
||||||
}
|
|
||||||
else if (commandsJsonArray->Size == 2)
|
|
||||||
{
|
|
||||||
value = CUnaryCommand(static_cast<int>(commandsJsonArray->GetNumberAt(0)), static_cast<int>(commandsJsonArray->GetNumberAt(1)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void RestoreJsonToSnapshot(Windows::Data::Json::JsonObject ^ jsonObject, std::optional<CBinaryCommand>& value)
|
|
||||||
{
|
|
||||||
value = CBinaryCommand(static_cast<int>(jsonObject->GetNamedNumber(L"Command")));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void RestoreJsonToSnapshot(Windows::Data::Json::JsonObject ^ jsonObject, std::optional<CParentheses>& value)
|
|
||||||
{
|
|
||||||
value = CParentheses(static_cast<int>(jsonObject->GetNamedNumber(L"Command")));
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::vector<std::pair<std::wstring, int>> RestoreExpressionTokensFromJsonArray(Windows::Data::Json::JsonArray ^ jsonArray)
|
|
||||||
{
|
|
||||||
std::vector<std::pair<std::wstring, int>> tokens;
|
|
||||||
for (uint32_t i = 0; i < jsonArray->Size; ++i)
|
|
||||||
{
|
|
||||||
auto tokenJsonArray = jsonArray->GetArrayAt(i);
|
|
||||||
if (tokenJsonArray->Size == 2 && tokenJsonArray->GetAt(0)->ValueType == Windows::Data::Json::JsonValueType::String
|
|
||||||
&& tokenJsonArray->GetAt(1)->ValueType == Windows::Data::Json::JsonValueType::Number)
|
|
||||||
{
|
|
||||||
tokens.emplace_back(std::wstring(tokenJsonArray->GetAt(0)->GetString()->Data()), static_cast<int>(tokenJsonArray->GetAt(1)->GetNumber()));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return tokens;
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::vector<std::shared_ptr<IExpressionCommand>> RestoreExpressionCommandsFromJsonArray(Windows::Data::Json::JsonArray ^ jsonArray)
|
|
||||||
{
|
|
||||||
std::vector<std::shared_ptr<IExpressionCommand>> commands;
|
|
||||||
for (uint32_t i = 0; i < jsonArray->Size; ++i)
|
|
||||||
{
|
|
||||||
std::optional<std::shared_ptr<IExpressionCommand>> command;
|
|
||||||
RestoreJsonToSnapshot(jsonArray->GetObjectAt(i), command);
|
|
||||||
if (command.has_value())
|
|
||||||
{
|
|
||||||
commands.push_back(*command);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return commands;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool IsJsonParsingException(Platform::COMException ^ e)
|
|
||||||
{
|
|
||||||
return e->HResult == WEB_E_JSON_VALUE_NOT_FOUND || e->HResult == E_ILLEGAL_METHOD_CALL;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ApplicationViewModel::ApplicationViewModel()
|
ApplicationViewModel::ApplicationViewModel()
|
||||||
|
@ -512,6 +72,17 @@ void ApplicationViewModel::Categories::set(IObservableVector<NavCategoryGroup ^>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CalculatorApp::ViewModel::Snapshot::ApplicationSnapshot ^ ApplicationViewModel::Snapshot::get()
|
||||||
|
{
|
||||||
|
auto snapshot = ref new CalculatorApp::ViewModel::Snapshot::ApplicationSnapshot();
|
||||||
|
snapshot->Mode = static_cast<int>(Mode);
|
||||||
|
if (m_CalculatorViewModel != nullptr && m_mode == ViewMode::Standard)
|
||||||
|
{
|
||||||
|
snapshot->StandardCalculator = m_CalculatorViewModel->Snapshot;
|
||||||
|
}
|
||||||
|
return snapshot;
|
||||||
|
}
|
||||||
|
|
||||||
void ApplicationViewModel::Initialize(ViewMode mode)
|
void ApplicationViewModel::Initialize(ViewMode mode)
|
||||||
{
|
{
|
||||||
if (!NavCategoryStates::IsValidViewMode(mode) || !NavCategoryStates::IsViewModeEnabled(mode))
|
if (!NavCategoryStates::IsValidViewMode(mode) || !NavCategoryStates::IsViewModeEnabled(mode))
|
||||||
|
@ -545,6 +116,15 @@ void ApplicationViewModel::Initialize(ViewMode mode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ApplicationViewModel::RestoreFromSnapshot(CalculatorApp::ViewModel::Snapshot::ApplicationSnapshot ^ snapshot)
|
||||||
|
{
|
||||||
|
Mode = static_cast<ViewMode>(snapshot->Mode);
|
||||||
|
if (snapshot->StandardCalculator != nullptr)
|
||||||
|
{
|
||||||
|
m_CalculatorViewModel->Snapshot = snapshot->StandardCalculator;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool ApplicationViewModel::TryRecoverFromNavigationModeFailure()
|
bool ApplicationViewModel::TryRecoverFromNavigationModeFailure()
|
||||||
{
|
{
|
||||||
// Here we are simply trying to recover from being unable to navigate to a mode.
|
// Here we are simply trying to recover from being unable to navigate to a mode.
|
||||||
|
@ -711,48 +291,3 @@ void ApplicationViewModel::SetDisplayNormalAlwaysOnTopOption()
|
||||||
DisplayNormalAlwaysOnTopOption =
|
DisplayNormalAlwaysOnTopOption =
|
||||||
m_mode == ViewMode::Standard && ApplicationView::GetForCurrentView()->IsViewModeSupported(ApplicationViewMode::CompactOverlay) && !IsAlwaysOnTop;
|
m_mode == ViewMode::Standard && ApplicationView::GetForCurrentView()->IsViewModeSupported(ApplicationViewMode::CompactOverlay) && !IsAlwaysOnTop;
|
||||||
}
|
}
|
||||||
|
|
||||||
Windows::Data::Json::JsonObject ^ ApplicationViewModel::SaveApplicationSnapshot()
|
|
||||||
{
|
|
||||||
ApplicationSnapshot applicationSnapshot;
|
|
||||||
applicationSnapshot.SnapshotVersion = SnapshotHelper::SnapshotVersion;
|
|
||||||
applicationSnapshot.Mode = static_cast<int>(Mode);
|
|
||||||
if (m_CalculatorViewModel != nullptr && m_mode == ViewMode::Standard)
|
|
||||||
{
|
|
||||||
// Standard calculator is the only supported mode so far.
|
|
||||||
applicationSnapshot.StandardCalc = m_CalculatorViewModel->GetStandardCalculatorSnapshot();
|
|
||||||
}
|
|
||||||
return SnapshotHelper::SaveSnapshotToJson(applicationSnapshot);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ApplicationViewModel::TryRestoreFromSnapshot(Windows::Data::Json::JsonObject ^ jsonObject)
|
|
||||||
{
|
|
||||||
std::optional<ApplicationSnapshot> applicationSnapshot;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
SnapshotHelper::RestoreJsonToSnapshot(jsonObject, applicationSnapshot);
|
|
||||||
}
|
|
||||||
catch (Platform::COMException ^ e)
|
|
||||||
{
|
|
||||||
if (SnapshotHelper::IsJsonParsingException(e))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (applicationSnapshot.has_value())
|
|
||||||
{
|
|
||||||
Mode = static_cast<ViewMode>(applicationSnapshot->Mode);
|
|
||||||
if (applicationSnapshot->StandardCalc.has_value())
|
|
||||||
{
|
|
||||||
if (m_CalculatorViewModel == nullptr)
|
|
||||||
{
|
|
||||||
m_CalculatorViewModel = ref new StandardCalculatorViewModel();
|
|
||||||
}
|
|
||||||
m_CalculatorViewModel->SetStandardCalculatorSnapshot(applicationSnapshot->StandardCalc.value());
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "Snapshots.h"
|
||||||
#include "StandardCalculatorViewModel.h"
|
#include "StandardCalculatorViewModel.h"
|
||||||
#include "DateCalculatorViewModel.h"
|
#include "DateCalculatorViewModel.h"
|
||||||
#include "GraphingCalculator/GraphingCalculatorViewModel.h"
|
#include "GraphingCalculator/GraphingCalculatorViewModel.h"
|
||||||
|
@ -12,19 +13,13 @@ namespace CalculatorApp
|
||||||
{
|
{
|
||||||
namespace ViewModel
|
namespace ViewModel
|
||||||
{
|
{
|
||||||
struct ApplicationSnapshot
|
|
||||||
{
|
|
||||||
int SnapshotVersion;
|
|
||||||
int Mode;
|
|
||||||
std::optional<StandardCalculatorSnapshot> StandardCalc;
|
|
||||||
};
|
|
||||||
|
|
||||||
[Windows::UI::Xaml::Data::Bindable] public ref class ApplicationViewModel sealed : public Windows::UI::Xaml::Data::INotifyPropertyChanged
|
[Windows::UI::Xaml::Data::Bindable] public ref class ApplicationViewModel sealed : public Windows::UI::Xaml::Data::INotifyPropertyChanged
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ApplicationViewModel();
|
ApplicationViewModel();
|
||||||
|
|
||||||
void Initialize(CalculatorApp::ViewModel::Common::ViewMode mode); // Use for first init, use deserialize for rehydration
|
void Initialize(CalculatorApp::ViewModel::Common::ViewMode mode); // Use for first init, use deserialize for rehydration
|
||||||
|
void RestoreFromSnapshot(CalculatorApp::ViewModel::Snapshot::ApplicationSnapshot^ snapshot);
|
||||||
|
|
||||||
OBSERVABLE_OBJECT();
|
OBSERVABLE_OBJECT();
|
||||||
OBSERVABLE_PROPERTY_RW(StandardCalculatorViewModel ^, CalculatorViewModel);
|
OBSERVABLE_PROPERTY_RW(StandardCalculatorViewModel ^, CalculatorViewModel);
|
||||||
|
@ -77,6 +72,11 @@ namespace CalculatorApp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
property CalculatorApp::ViewModel::Snapshot::ApplicationSnapshot ^ Snapshot
|
||||||
|
{
|
||||||
|
CalculatorApp::ViewModel::Snapshot::ApplicationSnapshot ^ get();
|
||||||
|
}
|
||||||
|
|
||||||
static property Platform::String ^ LaunchedLocalSettings
|
static property Platform::String ^ LaunchedLocalSettings
|
||||||
{
|
{
|
||||||
Platform::String ^ get()
|
Platform::String ^ get()
|
||||||
|
@ -103,9 +103,6 @@ namespace CalculatorApp
|
||||||
|
|
||||||
void ToggleAlwaysOnTop(float width, float height);
|
void ToggleAlwaysOnTop(float width, float height);
|
||||||
|
|
||||||
Windows::Data::Json::JsonObject ^ SaveApplicationSnapshot();
|
|
||||||
bool TryRestoreFromSnapshot(Windows::Data::Json::JsonObject ^ jsonObject);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool TryRecoverFromNavigationModeFailure();
|
bool TryRecoverFromNavigationModeFailure();
|
||||||
|
|
||||||
|
|
|
@ -338,6 +338,7 @@
|
||||||
<ClInclude Include="HistoryViewModel.h" />
|
<ClInclude Include="HistoryViewModel.h" />
|
||||||
<ClInclude Include="MemoryItemViewModel.h" />
|
<ClInclude Include="MemoryItemViewModel.h" />
|
||||||
<ClInclude Include="pch.h" />
|
<ClInclude Include="pch.h" />
|
||||||
|
<ClInclude Include="Snapshots.h" />
|
||||||
<ClInclude Include="StandardCalculatorViewModel.h" />
|
<ClInclude Include="StandardCalculatorViewModel.h" />
|
||||||
<ClInclude Include="targetver.h" />
|
<ClInclude Include="targetver.h" />
|
||||||
<ClInclude Include="UnitConverterViewModel.h" />
|
<ClInclude Include="UnitConverterViewModel.h" />
|
||||||
|
@ -380,6 +381,7 @@
|
||||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
|
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
|
||||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
|
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="Snapshots.cpp" />
|
||||||
<ClCompile Include="StandardCalculatorViewModel.cpp" />
|
<ClCompile Include="StandardCalculatorViewModel.cpp" />
|
||||||
<ClCompile Include="UnitConverterViewModel.cpp" />
|
<ClCompile Include="UnitConverterViewModel.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
|
@ -89,6 +89,7 @@
|
||||||
<ClCompile Include="MemoryItemViewModel.cpp" />
|
<ClCompile Include="MemoryItemViewModel.cpp" />
|
||||||
<ClCompile Include="StandardCalculatorViewModel.cpp" />
|
<ClCompile Include="StandardCalculatorViewModel.cpp" />
|
||||||
<ClCompile Include="UnitConverterViewModel.cpp" />
|
<ClCompile Include="UnitConverterViewModel.cpp" />
|
||||||
|
<ClCompile Include="Snapshots.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="pch.h" />
|
<ClInclude Include="pch.h" />
|
||||||
|
@ -203,6 +204,7 @@
|
||||||
<ClInclude Include="StandardCalculatorViewModel.h" />
|
<ClInclude Include="StandardCalculatorViewModel.h" />
|
||||||
<ClInclude Include="targetver.h" />
|
<ClInclude Include="targetver.h" />
|
||||||
<ClInclude Include="UnitConverterViewModel.h" />
|
<ClInclude Include="UnitConverterViewModel.h" />
|
||||||
|
<ClInclude Include="Snapshots.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="DataLoaders\DefaultFromToCurrency.json">
|
<None Include="DataLoaders\DefaultFromToCurrency.json">
|
||||||
|
|
|
@ -345,10 +345,9 @@ namespace CalculatorApp
|
||||||
TraceLoggingCommon::GetInstance()->LogLevel2Event(StringReference(EVENT_NAME_RECALL_RESTORE), fields);
|
TraceLoggingCommon::GetInstance()->LogLevel2Event(StringReference(EVENT_NAME_RECALL_RESTORE), fields);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TraceLogger::LogRecallError(CalculatorApp::ViewModel::Common::ViewMode mode, Platform::String^ message)
|
void TraceLogger::LogRecallError(Platform::String^ message)
|
||||||
{
|
{
|
||||||
auto fields = ref new LoggingFields();
|
auto fields = ref new LoggingFields();
|
||||||
fields->AddString(StringReference(CALC_MODE), NavCategoryStates::GetFriendlyName(mode));
|
|
||||||
fields->AddString(StringReference(L"FunctionName"), L"Recall");
|
fields->AddString(StringReference(L"FunctionName"), L"Recall");
|
||||||
fields->AddString(StringReference(L"Message"), message);
|
fields->AddString(StringReference(L"Message"), message);
|
||||||
TraceLoggingCommon::GetInstance()->LogLevel2Event(StringReference(EVENT_NAME_EXCEPTION), fields);
|
TraceLoggingCommon::GetInstance()->LogLevel2Event(StringReference(EVENT_NAME_EXCEPTION), fields);
|
||||||
|
|
|
@ -87,7 +87,7 @@ namespace CalculatorApp::ViewModel::Common
|
||||||
void LogPlatformExceptionInfo(CalculatorApp::ViewModel::Common::ViewMode mode, Platform::String ^ functionName, Platform::String ^ message, int hresult);
|
void LogPlatformExceptionInfo(CalculatorApp::ViewModel::Common::ViewMode mode, Platform::String ^ functionName, Platform::String ^ message, int hresult);
|
||||||
void LogRecallSnapshot(CalculatorApp::ViewModel::Common::ViewMode mode);
|
void LogRecallSnapshot(CalculatorApp::ViewModel::Common::ViewMode mode);
|
||||||
void LogRecallRestore(CalculatorApp::ViewModel::Common::ViewMode mode);
|
void LogRecallRestore(CalculatorApp::ViewModel::Common::ViewMode mode);
|
||||||
void LogRecallError(CalculatorApp::ViewModel::Common::ViewMode mode, Platform::String ^ message);
|
void LogRecallError(Platform::String ^ message);
|
||||||
|
|
||||||
internal:
|
internal:
|
||||||
void LogPlatformException(CalculatorApp::ViewModel::Common::ViewMode mode, Platform::String ^ functionName, Platform::Exception ^ e);
|
void LogPlatformException(CalculatorApp::ViewModel::Common::ViewMode mode, Platform::String ^ functionName, Platform::Exception ^ e);
|
||||||
|
|
281
src/CalcViewModel/Snapshots.cpp
Normal file
281
src/CalcViewModel/Snapshots.cpp
Normal file
|
@ -0,0 +1,281 @@
|
||||||
|
// Copyright (c) Microsoft Corporation.
|
||||||
|
// Licensed under the MIT License.
|
||||||
|
|
||||||
|
#include "pch.h"
|
||||||
|
#include <cassert>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "CalcManager/ExpressionCommand.h"
|
||||||
|
#include "Snapshots.h"
|
||||||
|
|
||||||
|
namespace CalculatorApp::ViewModel::Snapshot
|
||||||
|
{
|
||||||
|
UnaryCommand::UnaryCommand()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
UnaryCommand::UnaryCommand(std::vector<int> cmds)
|
||||||
|
: m_cmds(std::move(cmds))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Windows::Foundation::Collections::IVectorView<int> ^ UnaryCommand::Commands::get()
|
||||||
|
{
|
||||||
|
return ref new Platform::Collections::VectorView<int>(m_cmds);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UnaryCommand::Commands::set(Windows::Foundation::Collections::IVectorView<int> ^ commands)
|
||||||
|
{
|
||||||
|
m_cmds.clear();
|
||||||
|
for (auto cmd : commands)
|
||||||
|
{
|
||||||
|
m_cmds.push_back(cmd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BinaryCommand::BinaryCommand()
|
||||||
|
{
|
||||||
|
Command = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
BinaryCommand::BinaryCommand(int cmd)
|
||||||
|
{
|
||||||
|
Command = cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
OperandCommand::OperandCommand()
|
||||||
|
{
|
||||||
|
IsNegative = false;
|
||||||
|
IsDecimalPresent = false;
|
||||||
|
IsSciFmt = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
OperandCommand::OperandCommand(bool isNegative, bool isDecimal, bool isSciFmt, std::vector<int> cmds)
|
||||||
|
{
|
||||||
|
IsNegative = isNegative;
|
||||||
|
IsDecimalPresent = isDecimal;
|
||||||
|
IsSciFmt = isSciFmt;
|
||||||
|
m_cmds = std::move(cmds);
|
||||||
|
}
|
||||||
|
|
||||||
|
Windows::Foundation::Collections::IVectorView<int> ^ OperandCommand::Commands::get()
|
||||||
|
{
|
||||||
|
return ref new Platform::Collections::VectorView<int>(m_cmds);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OperandCommand::Commands::set(Windows::Foundation::Collections::IVectorView<int> ^ commands)
|
||||||
|
{
|
||||||
|
m_cmds.clear();
|
||||||
|
for (auto cmd : commands)
|
||||||
|
{
|
||||||
|
m_cmds.push_back(cmd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Parentheses::Parentheses()
|
||||||
|
{
|
||||||
|
Command = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Parentheses::Parentheses(int cmd)
|
||||||
|
{
|
||||||
|
Command = cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
ICalcManagerIExprCommand ^ CreateExprCommand(const IExpressionCommand* exprCmd) {
|
||||||
|
switch (exprCmd->GetCommandType())
|
||||||
|
{
|
||||||
|
case CalculationManager::CommandType::UnaryCommand:
|
||||||
|
{
|
||||||
|
auto cmd = static_cast<const IUnaryCommand*>(exprCmd);
|
||||||
|
std::vector<int> cmdlist;
|
||||||
|
for (auto& subcmd : *cmd->GetCommands())
|
||||||
|
{
|
||||||
|
cmdlist.push_back(subcmd);
|
||||||
|
}
|
||||||
|
return ref new UnaryCommand(std::move(cmdlist));
|
||||||
|
}
|
||||||
|
case CalculationManager::CommandType::BinaryCommand:
|
||||||
|
{
|
||||||
|
auto cmd = static_cast<const IBinaryCommand*>(exprCmd);
|
||||||
|
return ref new BinaryCommand(cmd->GetCommand());
|
||||||
|
}
|
||||||
|
case CalculationManager::CommandType::OperandCommand:
|
||||||
|
{
|
||||||
|
auto cmd = static_cast<const IOpndCommand*>(exprCmd);
|
||||||
|
std::vector<int> cmdlist;
|
||||||
|
for (auto& subcmd : *cmd->GetCommands())
|
||||||
|
{
|
||||||
|
cmdlist.push_back(subcmd);
|
||||||
|
}
|
||||||
|
return ref new OperandCommand(cmd->IsNegative(), cmd->IsDecimalPresent(), cmd->IsSciFmt(), std::move(cmdlist));
|
||||||
|
}
|
||||||
|
case CalculationManager::CommandType::Parentheses:
|
||||||
|
{
|
||||||
|
auto cmd = static_cast<const IParenthesisCommand*>(exprCmd);
|
||||||
|
return ref new Parentheses(cmd->GetCommand());
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
throw std::logic_error{ "unhandled command type." };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CalcManagerToken::CalcManagerToken()
|
||||||
|
{
|
||||||
|
OpCodeName = ref new Platform::String();
|
||||||
|
CommandIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
CalcManagerToken::CalcManagerToken(Platform::String ^ opCodeName, int cmdIndex)
|
||||||
|
{
|
||||||
|
assert(opCodeName != nullptr && "opCodeName is mandatory.");
|
||||||
|
OpCodeName = opCodeName;
|
||||||
|
CommandIndex = cmdIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
CalcManagerHistoryItem::CalcManagerHistoryItem()
|
||||||
|
{
|
||||||
|
Tokens = ref new Platform::Collections::Vector<CalcManagerToken ^>();
|
||||||
|
Commands = ref new Platform::Collections::Vector<ICalcManagerIExprCommand ^>();
|
||||||
|
Expression = ref new Platform::String();
|
||||||
|
Result = ref new Platform::String();
|
||||||
|
}
|
||||||
|
|
||||||
|
CalcManagerHistoryItem::CalcManagerHistoryItem(const CalculationManager::HISTORYITEM& item)
|
||||||
|
{
|
||||||
|
Tokens = ref new Platform::Collections::Vector<CalcManagerToken ^>();
|
||||||
|
assert(item.historyItemVector.spTokens != nullptr && "spTokens shall not be null.");
|
||||||
|
for (auto& [opCode, cmdIdx] : *item.historyItemVector.spTokens)
|
||||||
|
{
|
||||||
|
Tokens->Append(ref new CalcManagerToken(ref new Platform::String(opCode.c_str()), cmdIdx));
|
||||||
|
}
|
||||||
|
Commands = ref new Platform::Collections::Vector<ICalcManagerIExprCommand ^>();
|
||||||
|
assert(item.historyItemVector.spCommands != nullptr && "spCommands shall not be null.");
|
||||||
|
for (auto& cmd : *item.historyItemVector.spCommands)
|
||||||
|
{
|
||||||
|
Commands->Append(CreateExprCommand(cmd.get()));
|
||||||
|
}
|
||||||
|
Expression = ref new Platform::String(item.historyItemVector.expression.c_str());
|
||||||
|
Result = ref new Platform::String(item.historyItemVector.result.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
CalcManagerSnapshot::CalcManagerSnapshot()
|
||||||
|
{
|
||||||
|
HistoryItems = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
CalcManagerSnapshot::CalcManagerSnapshot(const CalculationManager::CalculatorManager& calcMgr)
|
||||||
|
{
|
||||||
|
auto& items = calcMgr.GetHistoryItems();
|
||||||
|
if (!items.empty())
|
||||||
|
{
|
||||||
|
HistoryItems = ref new Platform::Collections::Vector<CalcManagerHistoryItem ^>();
|
||||||
|
for (auto& item : items)
|
||||||
|
{
|
||||||
|
HistoryItems->Append(ref new CalcManagerHistoryItem(*item));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PrimaryDisplaySnapshot::PrimaryDisplaySnapshot()
|
||||||
|
{
|
||||||
|
DisplayValue = ref new Platform::String();
|
||||||
|
IsError = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
PrimaryDisplaySnapshot::PrimaryDisplaySnapshot(Platform::String ^ display, bool isError)
|
||||||
|
{
|
||||||
|
assert(display != nullptr && "display is mandatory");
|
||||||
|
DisplayValue = display;
|
||||||
|
IsError = isError;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpressionDisplaySnapshot::ExpressionDisplaySnapshot()
|
||||||
|
{
|
||||||
|
Tokens = ref new Platform::Collections::Vector<CalcManagerToken ^>();
|
||||||
|
Commands = ref new Platform::Collections::Vector<ICalcManagerIExprCommand ^>();
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpressionDisplaySnapshot::ExpressionDisplaySnapshot(
|
||||||
|
const std::vector<CalcHistoryToken>& tokens,
|
||||||
|
const std::vector<std::shared_ptr<IExpressionCommand>>& commands)
|
||||||
|
{
|
||||||
|
Tokens = ref new Platform::Collections::Vector<CalcManagerToken ^>();
|
||||||
|
for (auto& [opCode, cmdIdx] : tokens)
|
||||||
|
{
|
||||||
|
Tokens->Append(ref new CalcManagerToken(ref new Platform::String(opCode.c_str()), cmdIdx));
|
||||||
|
}
|
||||||
|
|
||||||
|
Commands = ref new Platform::Collections::Vector<ICalcManagerIExprCommand ^>();
|
||||||
|
for (auto& cmd : commands)
|
||||||
|
{
|
||||||
|
Commands->Append(CreateExprCommand(cmd.get()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StandardCalculatorSnapshot::StandardCalculatorSnapshot()
|
||||||
|
{
|
||||||
|
CalcManager = ref new CalcManagerSnapshot();
|
||||||
|
PrimaryDisplay = ref new PrimaryDisplaySnapshot();
|
||||||
|
ExpressionDisplay = nullptr;
|
||||||
|
DisplayCommands = ref new Platform::Collections::Vector<ICalcManagerIExprCommand ^>();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::shared_ptr<CalculationManager::HISTORYITEM>> ToUnderlying(Windows::Foundation::Collections::IVector<CalcManagerHistoryItem ^> ^ items)
|
||||||
|
{
|
||||||
|
std::vector<std::shared_ptr<CalculationManager::HISTORYITEM>> result;
|
||||||
|
for (CalcManagerHistoryItem ^ item : items)
|
||||||
|
{
|
||||||
|
CalculationManager::HISTORYITEMVECTOR nativeItem;
|
||||||
|
nativeItem.spTokens = std::make_shared<std::vector<std::pair<std::wstring, int>>>();
|
||||||
|
for (CalcManagerToken ^ token : item->Tokens)
|
||||||
|
{
|
||||||
|
nativeItem.spTokens->push_back(std::make_pair(token->OpCodeName->Data(), token->CommandIndex));
|
||||||
|
}
|
||||||
|
nativeItem.spCommands = std::make_shared<std::vector<std::shared_ptr<IExpressionCommand>>>(ToUnderlying(item->Commands));
|
||||||
|
nativeItem.expression = item->Expression->Data();
|
||||||
|
nativeItem.result = item->Result->Data();
|
||||||
|
auto spItem = std::make_shared<CalculationManager::HISTORYITEM>(CalculationManager::HISTORYITEM{ std::move(nativeItem) });
|
||||||
|
result.push_back(std::move(std::move(spItem)));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::shared_ptr<IExpressionCommand>> ToUnderlying(Windows::Foundation::Collections::IVector<ICalcManagerIExprCommand ^> ^ commands)
|
||||||
|
{
|
||||||
|
std::vector<std::shared_ptr<IExpressionCommand>> result;
|
||||||
|
for (ICalcManagerIExprCommand ^ cmdEntry : commands)
|
||||||
|
{
|
||||||
|
if (auto unary = dynamic_cast<UnaryCommand ^>(cmdEntry); unary != nullptr)
|
||||||
|
{
|
||||||
|
if (unary->m_cmds.size() == 1)
|
||||||
|
{
|
||||||
|
result.push_back(std::make_shared<CUnaryCommand>(unary->m_cmds[0]));
|
||||||
|
}
|
||||||
|
else if (unary->m_cmds.size() == 2)
|
||||||
|
{
|
||||||
|
result.push_back(std::make_shared<CUnaryCommand>(unary->m_cmds[0], unary->m_cmds[1]));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw std::logic_error{ "ill-formed command." };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (auto binary = dynamic_cast<BinaryCommand ^>(cmdEntry); binary != nullptr)
|
||||||
|
{
|
||||||
|
result.push_back(std::make_shared<CBinaryCommand>(binary->Command));
|
||||||
|
}
|
||||||
|
else if (auto paren = dynamic_cast<Parentheses ^>(cmdEntry); paren != nullptr)
|
||||||
|
{
|
||||||
|
result.push_back(std::make_shared<CParentheses>(paren->Command));
|
||||||
|
}
|
||||||
|
else if (auto operand = dynamic_cast<OperandCommand ^>(cmdEntry); operand != nullptr)
|
||||||
|
{
|
||||||
|
auto subcmds = std::make_shared<std::vector<int>>(operand->m_cmds);
|
||||||
|
result.push_back(std::make_shared<COpndCommand>(std::move(subcmds), operand->IsNegative, operand->IsDecimalPresent, operand->IsSciFmt));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
} // namespace CalculatorApp::ViewModel
|
156
src/CalcViewModel/Snapshots.h
Normal file
156
src/CalcViewModel/Snapshots.h
Normal file
|
@ -0,0 +1,156 @@
|
||||||
|
// Copyright (c) Microsoft Corporation.
|
||||||
|
// Licensed under the MIT License.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "CalcManager/CalculatorManager.h"
|
||||||
|
|
||||||
|
namespace CalculatorApp::ViewModel::Snapshot
|
||||||
|
{
|
||||||
|
public
|
||||||
|
interface struct ICalcManagerIExprCommand
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
public
|
||||||
|
ref struct UnaryCommand sealed : public ICalcManagerIExprCommand
|
||||||
|
{
|
||||||
|
property Windows::Foundation::Collections::IVectorView<int> ^ Commands {
|
||||||
|
Windows::Foundation::Collections::IVectorView<int> ^ get();
|
||||||
|
void set(Windows::Foundation::Collections::IVectorView<int> ^ commands);
|
||||||
|
};
|
||||||
|
|
||||||
|
UnaryCommand();
|
||||||
|
|
||||||
|
internal :;
|
||||||
|
explicit UnaryCommand(std::vector<int> cmds);
|
||||||
|
std::vector<int> m_cmds;
|
||||||
|
};
|
||||||
|
|
||||||
|
public
|
||||||
|
ref struct BinaryCommand sealed : public ICalcManagerIExprCommand
|
||||||
|
{
|
||||||
|
property int Command;
|
||||||
|
|
||||||
|
BinaryCommand();
|
||||||
|
|
||||||
|
internal :;
|
||||||
|
explicit BinaryCommand(int cmd);
|
||||||
|
};
|
||||||
|
|
||||||
|
public
|
||||||
|
ref struct OperandCommand sealed : public ICalcManagerIExprCommand
|
||||||
|
{
|
||||||
|
property bool IsNegative;
|
||||||
|
property bool IsDecimalPresent;
|
||||||
|
property bool IsSciFmt;
|
||||||
|
property Windows::Foundation::Collections::IVectorView<int> ^ Commands {
|
||||||
|
Windows::Foundation::Collections::IVectorView<int> ^ get();
|
||||||
|
void set(Windows::Foundation::Collections::IVectorView<int> ^ commands);
|
||||||
|
};
|
||||||
|
|
||||||
|
OperandCommand();
|
||||||
|
|
||||||
|
internal :;
|
||||||
|
explicit OperandCommand(bool isNegative, bool isDecimal, bool isSciFmt, std::vector<int> cmds);
|
||||||
|
std::vector<int> m_cmds;
|
||||||
|
};
|
||||||
|
|
||||||
|
public
|
||||||
|
ref struct Parentheses sealed : public ICalcManagerIExprCommand
|
||||||
|
{
|
||||||
|
property int Command;
|
||||||
|
|
||||||
|
Parentheses();
|
||||||
|
|
||||||
|
internal :;
|
||||||
|
explicit Parentheses(int cmd);
|
||||||
|
};
|
||||||
|
|
||||||
|
public
|
||||||
|
ref struct CalcManagerToken sealed
|
||||||
|
{
|
||||||
|
property Platform::String ^ OpCodeName; // mandatory
|
||||||
|
property int CommandIndex;
|
||||||
|
|
||||||
|
CalcManagerToken();
|
||||||
|
|
||||||
|
internal :;
|
||||||
|
explicit CalcManagerToken(Platform::String ^ opCodeName, int cmdIndex);
|
||||||
|
};
|
||||||
|
|
||||||
|
public
|
||||||
|
ref struct CalcManagerHistoryItem sealed
|
||||||
|
{
|
||||||
|
property Windows::Foundation::Collections::IVector<CalcManagerToken ^> ^ Tokens; // mandatory
|
||||||
|
property Windows::Foundation::Collections::IVector<ICalcManagerIExprCommand ^> ^ Commands; // mandatory
|
||||||
|
property Platform::String ^ Expression; // mandatory
|
||||||
|
property Platform::String ^ Result; // mandatory
|
||||||
|
|
||||||
|
CalcManagerHistoryItem();
|
||||||
|
|
||||||
|
internal :;
|
||||||
|
explicit CalcManagerHistoryItem(const CalculationManager::HISTORYITEM& item);
|
||||||
|
};
|
||||||
|
|
||||||
|
public
|
||||||
|
ref struct CalcManagerSnapshot sealed
|
||||||
|
{
|
||||||
|
property Windows::Foundation::Collections::IVector<CalcManagerHistoryItem ^> ^ HistoryItems; // optional
|
||||||
|
|
||||||
|
CalcManagerSnapshot();
|
||||||
|
|
||||||
|
internal :;
|
||||||
|
explicit CalcManagerSnapshot(const CalculationManager::CalculatorManager& calcMgr);
|
||||||
|
};
|
||||||
|
|
||||||
|
public
|
||||||
|
ref struct PrimaryDisplaySnapshot sealed
|
||||||
|
{
|
||||||
|
property Platform::String ^ DisplayValue; // mandatory
|
||||||
|
property bool IsError;
|
||||||
|
|
||||||
|
PrimaryDisplaySnapshot();
|
||||||
|
|
||||||
|
internal :;
|
||||||
|
explicit PrimaryDisplaySnapshot(Platform::String ^ display, bool isError);
|
||||||
|
};
|
||||||
|
|
||||||
|
public
|
||||||
|
ref struct ExpressionDisplaySnapshot sealed
|
||||||
|
{
|
||||||
|
property Windows::Foundation::Collections::IVector<CalcManagerToken ^> ^ Tokens;
|
||||||
|
property Windows::Foundation::Collections::IVector<ICalcManagerIExprCommand ^> ^ Commands;
|
||||||
|
|
||||||
|
ExpressionDisplaySnapshot();
|
||||||
|
|
||||||
|
internal :;
|
||||||
|
using CalcHistoryToken = std::pair<std::wstring, int>;
|
||||||
|
explicit ExpressionDisplaySnapshot(const std::vector<CalcHistoryToken>& tokens, const std::vector<std::shared_ptr<IExpressionCommand>>& commands);
|
||||||
|
};
|
||||||
|
|
||||||
|
public
|
||||||
|
ref struct StandardCalculatorSnapshot sealed
|
||||||
|
{
|
||||||
|
property CalcManagerSnapshot ^ CalcManager; // mandatory
|
||||||
|
property PrimaryDisplaySnapshot ^ PrimaryDisplay; // mandatory
|
||||||
|
property ExpressionDisplaySnapshot ^ ExpressionDisplay; // optional
|
||||||
|
property Windows::Foundation::Collections::IVector<ICalcManagerIExprCommand ^> ^ DisplayCommands; // mandatory
|
||||||
|
|
||||||
|
StandardCalculatorSnapshot();
|
||||||
|
};
|
||||||
|
|
||||||
|
public
|
||||||
|
ref struct ApplicationSnapshot sealed
|
||||||
|
{
|
||||||
|
property int Mode;
|
||||||
|
property StandardCalculatorSnapshot ^ StandardCalculator; // optional
|
||||||
|
};
|
||||||
|
|
||||||
|
ICalcManagerIExprCommand ^ CreateExprCommand(const IExpressionCommand* exprCmd);
|
||||||
|
std::vector<std::shared_ptr<IExpressionCommand>> ToUnderlying(Windows::Foundation::Collections::IVector<ICalcManagerIExprCommand ^> ^ commands);
|
||||||
|
std::vector<std::shared_ptr<CalculationManager::HISTORYITEM>> ToUnderlying(Windows::Foundation::Collections::IVector<CalcManagerHistoryItem ^> ^ items);
|
||||||
|
|
||||||
|
} // namespace CalculatorApp::ViewModel
|
|
@ -227,7 +227,7 @@ String ^ StandardCalculatorViewModel::CalculateNarratorDisplayValue(_In_ wstring
|
||||||
String ^ StandardCalculatorViewModel::GetNarratorStringReadRawNumbers(_In_ String ^ localizedDisplayValue)
|
String ^ StandardCalculatorViewModel::GetNarratorStringReadRawNumbers(_In_ String ^ localizedDisplayValue)
|
||||||
{
|
{
|
||||||
wstring ws;
|
wstring ws;
|
||||||
LocalizationSettings^ locSettings = LocalizationSettings::GetInstance();
|
LocalizationSettings ^ locSettings = LocalizationSettings::GetInstance();
|
||||||
|
|
||||||
// Insert a space after each digit in the string, to force Narrator to read them as separate numbers.
|
// Insert a space after each digit in the string, to force Narrator to read them as separate numbers.
|
||||||
for (const wchar_t& c : localizedDisplayValue)
|
for (const wchar_t& c : localizedDisplayValue)
|
||||||
|
@ -386,7 +386,7 @@ void StandardCalculatorViewModel::SetTokens(_Inout_ shared_ptr<vector<pair<wstri
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
LocalizationSettings^ localizer = LocalizationSettings::GetInstance();
|
LocalizationSettings ^ localizer = LocalizationSettings::GetInstance();
|
||||||
|
|
||||||
const wstring separator = L" ";
|
const wstring separator = L" ";
|
||||||
for (unsigned int i = 0; i < nTokens; ++i)
|
for (unsigned int i = 0; i < nTokens; ++i)
|
||||||
|
@ -449,7 +449,7 @@ String ^ StandardCalculatorViewModel::GetCalculatorExpressionAutomationName()
|
||||||
|
|
||||||
void StandardCalculatorViewModel::SetMemorizedNumbers(const vector<wstring>& newMemorizedNumbers)
|
void StandardCalculatorViewModel::SetMemorizedNumbers(const vector<wstring>& newMemorizedNumbers)
|
||||||
{
|
{
|
||||||
LocalizationSettings^ localizer = LocalizationSettings::GetInstance();
|
LocalizationSettings ^ localizer = LocalizationSettings::GetInstance();
|
||||||
if (newMemorizedNumbers.size() == 0) // Memory has been cleared
|
if (newMemorizedNumbers.size() == 0) // Memory has been cleared
|
||||||
{
|
{
|
||||||
MemorizedNumbers->Clear();
|
MemorizedNumbers->Clear();
|
||||||
|
@ -1060,8 +1060,8 @@ ButtonInfo StandardCalculatorViewModel::MapCharacterToButtonId(char16 ch)
|
||||||
{
|
{
|
||||||
if (LocalizationSettings::GetInstance()->IsLocalizedDigit(ch))
|
if (LocalizationSettings::GetInstance()->IsLocalizedDigit(ch))
|
||||||
{
|
{
|
||||||
result.buttonId =
|
result.buttonId = NumbersAndOperatorsEnum::Zero
|
||||||
NumbersAndOperatorsEnum::Zero + static_cast<NumbersAndOperatorsEnum>(ch - LocalizationSettings::GetInstance()->GetDigitSymbolFromEnUsDigit('0'));
|
+ static_cast<NumbersAndOperatorsEnum>(ch - LocalizationSettings::GetInstance()->GetDigitSymbolFromEnUsDigit('0'));
|
||||||
result.canSendNegate = true;
|
result.canSendNegate = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1588,7 +1588,7 @@ void StandardCalculatorViewModel::UpdateProgrammerPanelDisplay()
|
||||||
binaryDisplayString = m_standardCalculatorManager.GetResultForRadix(2, precision, true);
|
binaryDisplayString = m_standardCalculatorManager.GetResultForRadix(2, precision, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LocalizationSettings^ localizer = LocalizationSettings::GetInstance();
|
LocalizationSettings ^ localizer = LocalizationSettings::GetInstance();
|
||||||
binaryDisplayString = AddPadding(binaryDisplayString);
|
binaryDisplayString = AddPadding(binaryDisplayString);
|
||||||
|
|
||||||
localizer->LocalizeDisplayValue(&hexDisplayString);
|
localizer->LocalizeDisplayValue(&hexDisplayString);
|
||||||
|
@ -1787,49 +1787,56 @@ void StandardCalculatorViewModel::SetBitshiftRadioButtonCheckedAnnouncement(Plat
|
||||||
Announcement = CalculatorAnnouncement::GetBitShiftRadioButtonCheckedAnnouncement(announcement);
|
Announcement = CalculatorAnnouncement::GetBitShiftRadioButtonCheckedAnnouncement(announcement);
|
||||||
}
|
}
|
||||||
|
|
||||||
StandardCalculatorSnapshot StandardCalculatorViewModel::GetStandardCalculatorSnapshot() const
|
CalculatorApp::ViewModel::Snapshot::StandardCalculatorSnapshot ^ StandardCalculatorViewModel::Snapshot::get()
|
||||||
{
|
{
|
||||||
StandardCalculatorSnapshot snapshot;
|
auto result = ref new CalculatorApp::ViewModel::Snapshot::StandardCalculatorSnapshot();
|
||||||
auto& historyItems = m_standardCalculatorManager.GetHistoryItems();
|
result->CalcManager = ref new CalculatorApp::ViewModel::Snapshot::CalcManagerSnapshot(m_standardCalculatorManager);
|
||||||
if (!historyItems.empty())
|
result->PrimaryDisplay = ref new CalculatorApp::ViewModel::Snapshot::PrimaryDisplaySnapshot(m_DisplayValue, m_IsInError);
|
||||||
{
|
|
||||||
snapshot.CalcManager.HistoryItems = std::move(historyItems);
|
|
||||||
}
|
|
||||||
snapshot.PrimaryDisplay = PrimaryDisplaySnapshot{ m_DisplayValue, m_IsInError };
|
|
||||||
if (!m_tokens->empty() && !m_commands->empty())
|
if (!m_tokens->empty() && !m_commands->empty())
|
||||||
{
|
{
|
||||||
snapshot.ExpressionDisplay = { *m_tokens, *m_commands };
|
result->ExpressionDisplay = ref new CalculatorApp::ViewModel::Snapshot::ExpressionDisplaySnapshot(*m_tokens, *m_commands);
|
||||||
}
|
}
|
||||||
snapshot.DisplayCommands = m_standardCalculatorManager.GetDisplayCommandsSnapshot();
|
result->DisplayCommands = ref new Platform::Collections::Vector<CalculatorApp::ViewModel::Snapshot::ICalcManagerIExprCommand ^>();
|
||||||
return snapshot;
|
for (auto cmd : m_standardCalculatorManager.GetDisplayCommandsSnapshot())
|
||||||
|
{
|
||||||
|
result->DisplayCommands->Append(CalculatorApp::ViewModel::Snapshot::CreateExprCommand(cmd.get()));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void StandardCalculatorViewModel::SetStandardCalculatorSnapshot(const StandardCalculatorSnapshot& snapshot)
|
void CalculatorApp::ViewModel::StandardCalculatorViewModel::Snapshot::set(CalculatorApp::ViewModel::Snapshot::StandardCalculatorSnapshot ^ snapshot)
|
||||||
{
|
{
|
||||||
if (snapshot.CalcManager.HistoryItems.has_value())
|
assert(snapshot != nullptr);
|
||||||
|
m_standardCalculatorManager.Reset();
|
||||||
|
if (snapshot->CalcManager->HistoryItems != nullptr)
|
||||||
{
|
{
|
||||||
m_standardCalculatorManager.SetHistoryItems(snapshot.CalcManager.HistoryItems.value());
|
m_standardCalculatorManager.SetHistoryItems(ToUnderlying(snapshot->CalcManager->HistoryItems));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<int> commands;
|
std::vector<int> commands;
|
||||||
if (snapshot.ExpressionDisplay.has_value() && snapshot.ExpressionDisplay->Tokens.back().first == L"=")
|
if (snapshot->ExpressionDisplay != nullptr && snapshot->ExpressionDisplay->Tokens->GetAt(snapshot->ExpressionDisplay->Tokens->Size - 1)->OpCodeName == L"=")
|
||||||
{
|
{
|
||||||
commands = GetCommandsFromExpressionCommands(snapshot.ExpressionDisplay->Commands);
|
commands = GetCommandsFromExpressionCommands(ToUnderlying(snapshot->ExpressionDisplay->Commands));
|
||||||
}
|
}
|
||||||
if (commands.empty() && !snapshot.DisplayCommands.empty())
|
if (commands.empty() && snapshot->DisplayCommands->Size > 0)
|
||||||
{
|
{
|
||||||
commands = GetCommandsFromExpressionCommands(snapshot.DisplayCommands);
|
commands = GetCommandsFromExpressionCommands(ToUnderlying(snapshot->DisplayCommands));
|
||||||
}
|
}
|
||||||
for (const auto& command : commands)
|
for (auto cmd : commands)
|
||||||
{
|
{
|
||||||
m_standardCalculatorManager.SendCommand(static_cast<Command>(command));
|
m_standardCalculatorManager.SendCommand(static_cast<Command>(cmd));
|
||||||
}
|
}
|
||||||
|
if (snapshot->ExpressionDisplay != nullptr)
|
||||||
if (snapshot.ExpressionDisplay.has_value())
|
|
||||||
{
|
{
|
||||||
|
using RawTokenCollection = std::vector<std::pair<std::wstring, int>>;
|
||||||
|
RawTokenCollection rawTokens;
|
||||||
|
for (CalculatorApp::ViewModel::Snapshot::CalcManagerToken ^ token : snapshot->ExpressionDisplay->Tokens)
|
||||||
|
{
|
||||||
|
rawTokens.push_back(std::pair{ token->OpCodeName->Data(), token->CommandIndex });
|
||||||
|
}
|
||||||
SetExpressionDisplay(
|
SetExpressionDisplay(
|
||||||
std::make_shared<std::vector<std::pair<std::wstring, int>>>(snapshot.ExpressionDisplay->Tokens),
|
std::make_shared<RawTokenCollection>(rawTokens),
|
||||||
std::make_shared<std::vector<std::shared_ptr<IExpressionCommand>>>(snapshot.ExpressionDisplay->Commands));
|
std::make_shared<std::vector<std::shared_ptr<IExpressionCommand>>>(ToUnderlying(snapshot->ExpressionDisplay->Commands)));
|
||||||
}
|
}
|
||||||
SetPrimaryDisplay(snapshot.PrimaryDisplay.DisplayValue, snapshot.PrimaryDisplay.IsError);
|
SetPrimaryDisplay(snapshot->PrimaryDisplay->DisplayValue, snapshot->PrimaryDisplay->IsError);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,11 +7,13 @@
|
||||||
#include "Common/CalculatorDisplay.h"
|
#include "Common/CalculatorDisplay.h"
|
||||||
#include "Common/EngineResourceProvider.h"
|
#include "Common/EngineResourceProvider.h"
|
||||||
#include "Common/CalculatorButtonUser.h"
|
#include "Common/CalculatorButtonUser.h"
|
||||||
#include "HistoryViewModel.h"
|
|
||||||
#include "MemoryItemViewModel.h"
|
|
||||||
#include "Common/BitLength.h"
|
#include "Common/BitLength.h"
|
||||||
#include "Common/NumberBase.h"
|
#include "Common/NumberBase.h"
|
||||||
|
|
||||||
|
#include "HistoryViewModel.h"
|
||||||
|
#include "MemoryItemViewModel.h"
|
||||||
|
#include "Snapshots.h"
|
||||||
|
|
||||||
namespace CalculatorUnitTests
|
namespace CalculatorUnitTests
|
||||||
{
|
{
|
||||||
class MultiWindowUnitTests;
|
class MultiWindowUnitTests;
|
||||||
|
@ -25,43 +27,19 @@ namespace CalculatorApp
|
||||||
namespace ViewModel
|
namespace ViewModel
|
||||||
{
|
{
|
||||||
#define ASCII_0 48
|
#define ASCII_0 48
|
||||||
public delegate void HideMemoryClickedHandler();
|
public
|
||||||
|
delegate void HideMemoryClickedHandler();
|
||||||
|
|
||||||
public value struct ButtonInfo
|
public
|
||||||
|
value struct ButtonInfo
|
||||||
{
|
{
|
||||||
CalculatorApp::ViewModel::Common::NumbersAndOperatorsEnum buttonId;
|
CalculatorApp::ViewModel::Common::NumbersAndOperatorsEnum buttonId;
|
||||||
bool canSendNegate;
|
bool canSendNegate;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CalculatorManagerSnapshot
|
|
||||||
{
|
|
||||||
std::optional<std::vector<std::shared_ptr<CalculationManager::HISTORYITEM>>> HistoryItems;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct PrimaryDisplaySnapshot
|
|
||||||
{
|
|
||||||
Platform::String ^ DisplayValue;
|
|
||||||
bool IsError = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ExpressionDisplaySnapshot
|
|
||||||
{
|
|
||||||
std::vector<std::pair<std::wstring, int>> Tokens;
|
|
||||||
std::vector<std::shared_ptr<IExpressionCommand>> Commands;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct StandardCalculatorSnapshot
|
|
||||||
{
|
|
||||||
CalculatorManagerSnapshot CalcManager;
|
|
||||||
PrimaryDisplaySnapshot PrimaryDisplay;
|
|
||||||
std::optional<ExpressionDisplaySnapshot> ExpressionDisplay;
|
|
||||||
std::vector<std::shared_ptr<IExpressionCommand>> DisplayCommands;
|
|
||||||
};
|
|
||||||
|
|
||||||
[Windows::UI::Xaml::Data::Bindable] public ref class StandardCalculatorViewModel sealed : public Windows::UI::Xaml::Data::INotifyPropertyChanged
|
[Windows::UI::Xaml::Data::Bindable] public ref class StandardCalculatorViewModel sealed : public Windows::UI::Xaml::Data::INotifyPropertyChanged
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
StandardCalculatorViewModel();
|
|
||||||
void UpdateOperand(int pos, Platform::String ^ text);
|
void UpdateOperand(int pos, Platform::String ^ text);
|
||||||
|
|
||||||
OBSERVABLE_OBJECT_CALLBACK(OnPropertyChanged);
|
OBSERVABLE_OBJECT_CALLBACK(OnPropertyChanged);
|
||||||
|
@ -265,6 +243,11 @@ namespace CalculatorApp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
property CalculatorApp::ViewModel::Snapshot::StandardCalculatorSnapshot ^ Snapshot {
|
||||||
|
CalculatorApp::ViewModel::Snapshot::StandardCalculatorSnapshot ^ get();
|
||||||
|
void set(CalculatorApp::ViewModel::Snapshot::StandardCalculatorSnapshot ^ snapshot);
|
||||||
|
};
|
||||||
|
|
||||||
// Used by unit tests
|
// Used by unit tests
|
||||||
void ResetCalcManager(bool clearMemory);
|
void ResetCalcManager(bool clearMemory);
|
||||||
void SendCommandToCalcManager(int command);
|
void SendCommandToCalcManager(int command);
|
||||||
|
@ -284,8 +267,7 @@ namespace CalculatorApp
|
||||||
void SwitchAngleType(CalculatorApp::ViewModel::Common::NumbersAndOperatorsEnum num);
|
void SwitchAngleType(CalculatorApp::ViewModel::Common::NumbersAndOperatorsEnum num);
|
||||||
void FtoEButtonToggled();
|
void FtoEButtonToggled();
|
||||||
|
|
||||||
internal:
|
internal : void OnPaste(Platform::String ^ pastedString);
|
||||||
void OnPaste(Platform::String ^ pastedString);
|
|
||||||
void OnCopyCommand(Platform::Object ^ parameter);
|
void OnCopyCommand(Platform::Object ^ parameter);
|
||||||
void OnPasteCommand(Platform::Object ^ parameter);
|
void OnPasteCommand(Platform::Object ^ parameter);
|
||||||
|
|
||||||
|
@ -320,8 +302,8 @@ namespace CalculatorApp
|
||||||
return m_CurrentAngleType;
|
return m_CurrentAngleType;
|
||||||
}
|
}
|
||||||
|
|
||||||
StandardCalculatorSnapshot GetStandardCalculatorSnapshot() const;
|
internal :;
|
||||||
void SetStandardCalculatorSnapshot(const StandardCalculatorSnapshot& state);
|
explicit StandardCalculatorViewModel();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void SetMemorizedNumbers(const std::vector<std::wstring>& memorizedNumbers);
|
void SetMemorizedNumbers(const std::vector<std::wstring>& memorizedNumbers);
|
||||||
|
@ -372,8 +354,7 @@ namespace CalculatorApp
|
||||||
Common::DisplayExpressionToken ^ m_selectedExpressionToken;
|
Common::DisplayExpressionToken ^ m_selectedExpressionToken;
|
||||||
|
|
||||||
Platform::String ^ LocalizeDisplayValue(_In_ std::wstring const& displayValue);
|
Platform::String ^ LocalizeDisplayValue(_In_ std::wstring const& displayValue);
|
||||||
Platform::String
|
Platform::String ^ CalculateNarratorDisplayValue(_In_ std::wstring const& displayValue, _In_ Platform::String ^ localizedDisplayValue);
|
||||||
^ CalculateNarratorDisplayValue(_In_ std::wstring const& displayValue, _In_ Platform::String ^ localizedDisplayValue);
|
|
||||||
CalculatorApp::ViewModel::Common::Automation::NarratorAnnouncement ^ GetDisplayUpdatedNarratorAnnouncement();
|
CalculatorApp::ViewModel::Common::Automation::NarratorAnnouncement ^ GetDisplayUpdatedNarratorAnnouncement();
|
||||||
Platform::String ^ GetCalculatorExpressionAutomationName();
|
Platform::String ^ GetCalculatorExpressionAutomationName();
|
||||||
Platform::String ^ GetNarratorStringReadRawNumbers(_In_ Platform::String ^ localizedDisplayValue);
|
Platform::String ^ GetNarratorStringReadRawNumbers(_In_ Platform::String ^ localizedDisplayValue);
|
||||||
|
|
|
@ -333,6 +333,7 @@
|
||||||
<ClInclude Include="..\CalcViewModel\HistoryViewModel.h" />
|
<ClInclude Include="..\CalcViewModel\HistoryViewModel.h" />
|
||||||
<ClInclude Include="..\CalcViewModel\MemoryItemViewModel.h" />
|
<ClInclude Include="..\CalcViewModel\MemoryItemViewModel.h" />
|
||||||
<ClInclude Include="..\CalcViewModel\pch.h" />
|
<ClInclude Include="..\CalcViewModel\pch.h" />
|
||||||
|
<ClInclude Include="..\CalcViewModel\Snapshots.h" />
|
||||||
<ClInclude Include="..\CalcViewModel\StandardCalculatorViewModel.h" />
|
<ClInclude Include="..\CalcViewModel\StandardCalculatorViewModel.h" />
|
||||||
<ClInclude Include="..\CalcViewModel\targetver.h" />
|
<ClInclude Include="..\CalcViewModel\targetver.h" />
|
||||||
<ClInclude Include="..\CalcViewModel\UnitConverterViewModel.h" />
|
<ClInclude Include="..\CalcViewModel\UnitConverterViewModel.h" />
|
||||||
|
@ -375,6 +376,7 @@
|
||||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
|
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
|
||||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
|
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\CalcViewModel\Snapshots.cpp" />
|
||||||
<ClCompile Include="..\CalcViewModel\StandardCalculatorViewModel.cpp" />
|
<ClCompile Include="..\CalcViewModel\StandardCalculatorViewModel.cpp" />
|
||||||
<ClCompile Include="..\CalcViewModel\UnitConverterViewModel.cpp" />
|
<ClCompile Include="..\CalcViewModel\UnitConverterViewModel.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
@ -392,6 +394,14 @@
|
||||||
<ItemDefinitionGroup Condition="!Exists('..\CalcViewModel\DataLoaders\DataLoaderConstants.h')">
|
<ItemDefinitionGroup Condition="!Exists('..\CalcViewModel\DataLoaders\DataLoaderConstants.h')">
|
||||||
<ClCompile>
|
<ClCompile>
|
||||||
<AdditionalOptions>/DUSE_MOCK_DATA %(AdditionalOptions)</AdditionalOptions>
|
<AdditionalOptions>/DUSE_MOCK_DATA %(AdditionalOptions)</AdditionalOptions>
|
||||||
|
<LanguageStandard Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">stdcpp17</LanguageStandard>
|
||||||
|
<LanguageStandard Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">stdcpp17</LanguageStandard>
|
||||||
|
<LanguageStandard Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">stdcpp17</LanguageStandard>
|
||||||
|
<LanguageStandard Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">stdcpp17</LanguageStandard>
|
||||||
|
<LanguageStandard Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">stdcpp17</LanguageStandard>
|
||||||
|
<LanguageStandard Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">stdcpp17</LanguageStandard>
|
||||||
|
<LanguageStandard Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">stdcpp17</LanguageStandard>
|
||||||
|
<LanguageStandard Condition="'$(Configuration)|$(Platform)'=='Release|x64'">stdcpp17</LanguageStandard>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<Choose>
|
<Choose>
|
||||||
|
|
|
@ -87,6 +87,7 @@
|
||||||
<Filter>GraphingCalculator</Filter>
|
<Filter>GraphingCalculator</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="..\CalcViewModel\Common\RadixType.cpp" />
|
<ClCompile Include="..\CalcViewModel\Common\RadixType.cpp" />
|
||||||
|
<ClCompile Include="..\CalcViewModel\Snapshots.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="..\CalcViewModel\Common\AppResourceProvider.h">
|
<ClInclude Include="..\CalcViewModel\Common\AppResourceProvider.h">
|
||||||
|
@ -204,6 +205,7 @@
|
||||||
<ClInclude Include="..\CalcViewModel\Common\AlwaysSelectedCollectionView.h">
|
<ClInclude Include="..\CalcViewModel\Common\AlwaysSelectedCollectionView.h">
|
||||||
<Filter>Common</Filter>
|
<Filter>Common</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\CalcViewModel\Snapshots.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="..\CalcViewModel\DataLoaders\DefaultFromToCurrency.json">
|
<None Include="..\CalcViewModel\DataLoaders\DefaultFromToCurrency.json">
|
||||||
|
|
|
@ -73,18 +73,13 @@ namespace CalculatorApp
|
||||||
|
|
||||||
protected override void OnActivated(IActivatedEventArgs args)
|
protected override void OnActivated(IActivatedEventArgs args)
|
||||||
{
|
{
|
||||||
if (args.Kind != ActivationKind.Protocol) return;
|
if (args.Kind != ActivationKind.Protocol)
|
||||||
|
|
||||||
if (args.IsSnapshotProtocol())
|
|
||||||
{
|
{
|
||||||
var protoArgs = (IProtocolActivatedEventArgs)args;
|
return;
|
||||||
OnAppLaunch(args,
|
}
|
||||||
new SnapshotLaunchArguments
|
else if (args.TryGetSnapshotProtocol(out var protoArgs))
|
||||||
{
|
{
|
||||||
ActivityId = protoArgs.Uri.GetActivityId(),
|
OnAppLaunch(args, protoArgs.GetSnapshotLaunchArgs(), false);
|
||||||
LaunchUri = protoArgs.Uri
|
|
||||||
},
|
|
||||||
false);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -165,8 +165,10 @@
|
||||||
<Compile Include="Converters\RadixToStringConverter.cs" />
|
<Compile Include="Converters\RadixToStringConverter.cs" />
|
||||||
<Compile Include="Converters\VisibilityNegationConverter.cs" />
|
<Compile Include="Converters\VisibilityNegationConverter.cs" />
|
||||||
<Compile Include="Selectors\NavViewMenuItemTemplateSelector.cs" />
|
<Compile Include="Selectors\NavViewMenuItemTemplateSelector.cs" />
|
||||||
|
<Compile Include="Utils\DeflateUtils.cs" />
|
||||||
<Compile Include="Utils\ResourceVirtualKey.cs" />
|
<Compile Include="Utils\ResourceVirtualKey.cs" />
|
||||||
<Compile Include="Utils\ResourceString.cs" />
|
<Compile Include="Utils\ResourceString.cs" />
|
||||||
|
<Compile Include="Utils\JsonUtils.cs" />
|
||||||
<Compile Include="Utils\ThemeHelper.cs" />
|
<Compile Include="Utils\ThemeHelper.cs" />
|
||||||
<Compile Include="Views\GraphingCalculator\EquationStylePanelControl.xaml.cs">
|
<Compile Include="Views\GraphingCalculator\EquationStylePanelControl.xaml.cs">
|
||||||
<DependentUpon>EquationStylePanelControl.xaml</DependentUpon>
|
<DependentUpon>EquationStylePanelControl.xaml</DependentUpon>
|
||||||
|
@ -799,6 +801,9 @@
|
||||||
<Version>6.2.14</Version>
|
<Version>6.2.14</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Microsoft.UI.Xaml" Version="2.8.1" />
|
<PackageReference Include="Microsoft.UI.Xaml" Version="2.8.1" />
|
||||||
|
<PackageReference Include="System.Text.Json">
|
||||||
|
<Version>8.0.5</Version>
|
||||||
|
</PackageReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\CalcViewModel\CalcViewModel.vcxproj">
|
<ProjectReference Include="..\CalcViewModel\CalcViewModel.vcxproj">
|
||||||
|
|
|
@ -1,48 +1,53 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text.Json;
|
||||||
using Windows.ApplicationModel.Activation;
|
using Windows.ApplicationModel.Activation;
|
||||||
using Windows.ApplicationModel.UserActivities;
|
|
||||||
|
using CalculatorApp.ViewModel.Snapshot;
|
||||||
|
using CalculatorApp.JsonUtils;
|
||||||
|
using CalculatorApp.ViewModel.Common;
|
||||||
|
|
||||||
namespace CalculatorApp
|
namespace CalculatorApp
|
||||||
{
|
{
|
||||||
internal class SnapshotLaunchArguments
|
internal class SnapshotLaunchArguments
|
||||||
{
|
{
|
||||||
public string ActivityId { get; set; }
|
public bool HasError { get; set; }
|
||||||
public Uri LaunchUri { get; set; }
|
public ApplicationSnapshot Snapshot { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static class LaunchExtensions
|
internal static class LaunchExtensions
|
||||||
{
|
{
|
||||||
public static bool IsSnapshotProtocol(this IActivatedEventArgs args) =>
|
public static bool TryGetSnapshotProtocol(this IActivatedEventArgs args, out IProtocolActivatedEventArgs result)
|
||||||
args is IProtocolActivatedEventArgs protoArgs &&
|
|
||||||
protoArgs.Uri != null &&
|
|
||||||
protoArgs.Uri.Segments != null &&
|
|
||||||
protoArgs.Uri.Segments.Length == 2 &&
|
|
||||||
protoArgs.Uri.Segments[0] == "snapshots/";
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// GetActivityId() requires the parameter `launchUri` to be a well-formed
|
|
||||||
/// snapshot URI.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="launchUri">the Uri to launch with a snapshot context.</param>
|
|
||||||
/// <returns>Activity ID</returns>
|
|
||||||
public static string GetActivityId(this Uri launchUri)
|
|
||||||
{
|
{
|
||||||
return launchUri.Segments[1].Trim();
|
result = null;
|
||||||
}
|
var protoArgs = args as IProtocolActivatedEventArgs;
|
||||||
|
if (protoArgs == null ||
|
||||||
public static bool VerifyIncomingActivity(this SnapshotLaunchArguments launchArgs, UserActivity activity)
|
protoArgs.Uri == null ||
|
||||||
{
|
protoArgs.Uri.Segments == null ||
|
||||||
if (activity.State != UserActivityState.Published ||
|
protoArgs.Uri.Segments.Length < 2 ||
|
||||||
string.IsNullOrEmpty(activity.ActivityId) ||
|
protoArgs.Uri.Segments[0] != "snapshot/")
|
||||||
activity.ActivationUri == null ||
|
|
||||||
activity.ActivationUri.Segments == null ||
|
|
||||||
activity.ActivationUri.Segments.Length != 2 ||
|
|
||||||
activity.ActivationUri.Segments[0] != "snapshots/")
|
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return activity.ActivityId == GetActivityId(launchArgs.LaunchUri);
|
result = protoArgs;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SnapshotLaunchArguments GetSnapshotLaunchArgs(this IProtocolActivatedEventArgs args)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var rawbase64 = args.Uri.Segments.Skip(1).Aggregate((folded, x) => folded += x);
|
||||||
|
var compressed = Convert.FromBase64String(rawbase64);
|
||||||
|
var jsonStr = DeflateUtils.Decompress(compressed);
|
||||||
|
var snapshot = JsonSerializer.Deserialize<ApplicationSnapshotAlias>(jsonStr);
|
||||||
|
return new SnapshotLaunchArguments { HasError = false, Snapshot = snapshot.Value };
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
TraceLogger.GetInstance().LogRecallError($"Error occurs during the deserialization of Snapshot. Exception: {ex}");
|
||||||
|
return new SnapshotLaunchArguments { HasError = true };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
35
src/Calculator/Utils/DeflateUtils.cs
Normal file
35
src/Calculator/Utils/DeflateUtils.cs
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.IO.Compression;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace CalculatorApp
|
||||||
|
{
|
||||||
|
internal static class DeflateUtils
|
||||||
|
{
|
||||||
|
public static byte[] Compress(string text)
|
||||||
|
{
|
||||||
|
var data = Encoding.UTF8.GetBytes(text);
|
||||||
|
using (var compressed = new MemoryStream())
|
||||||
|
{
|
||||||
|
using (var deflater = new DeflateStream(compressed, CompressionLevel.Optimal))
|
||||||
|
{
|
||||||
|
deflater.Write(data, 0, data.Length);
|
||||||
|
}
|
||||||
|
return compressed.ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string Decompress(byte[] data)
|
||||||
|
{
|
||||||
|
using (var srcStream = new MemoryStream(data))
|
||||||
|
using (var inflater = new DeflateStream(srcStream, CompressionMode.Decompress))
|
||||||
|
using (var resultStream = new MemoryStream())
|
||||||
|
{
|
||||||
|
inflater.CopyTo(resultStream);
|
||||||
|
byte[] decompressed = resultStream.ToArray();
|
||||||
|
return Encoding.UTF8.GetString(decompressed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
330
src/Calculator/Utils/JsonUtils.cs
Normal file
330
src/Calculator/Utils/JsonUtils.cs
Normal file
|
@ -0,0 +1,330 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
using CalculatorApp.ViewModel.Snapshot;
|
||||||
|
using Windows.ApplicationModel;
|
||||||
|
|
||||||
|
namespace CalculatorApp.JsonUtils
|
||||||
|
{
|
||||||
|
internal class CalcManagerTokenAlias
|
||||||
|
{
|
||||||
|
[JsonIgnore]
|
||||||
|
public CalcManagerToken Value;
|
||||||
|
|
||||||
|
[JsonPropertyName("t")]
|
||||||
|
public string OpCodeName
|
||||||
|
{
|
||||||
|
get => Value.OpCodeName;
|
||||||
|
set => Value.OpCodeName = value;
|
||||||
|
}
|
||||||
|
[JsonPropertyName("c")]
|
||||||
|
public int CommandIndex
|
||||||
|
{
|
||||||
|
get => Value.CommandIndex;
|
||||||
|
set => Value.CommandIndex = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CalcManagerTokenAlias() => Value = new CalcManagerToken();
|
||||||
|
public CalcManagerTokenAlias(CalcManagerToken value) => Value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
[JsonPolymorphic(TypeDiscriminatorPropertyName = "$t")]
|
||||||
|
[JsonDerivedType(typeof(UnaryCommandAlias), typeDiscriminator: 0)]
|
||||||
|
[JsonDerivedType(typeof(BinaryCommandAlias), typeDiscriminator: 1)]
|
||||||
|
[JsonDerivedType(typeof(OperandCommandAlias), typeDiscriminator: 2)]
|
||||||
|
[JsonDerivedType(typeof(ParenthesesAlias), typeDiscriminator: 3)]
|
||||||
|
internal interface ICalcManagerIExprCommandAlias
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class UnaryCommandAlias : ICalcManagerIExprCommandAlias
|
||||||
|
{
|
||||||
|
[JsonIgnore]
|
||||||
|
public UnaryCommand Value;
|
||||||
|
|
||||||
|
[JsonPropertyName("c")]
|
||||||
|
public IReadOnlyList<int> Commands
|
||||||
|
{
|
||||||
|
get => Value.Commands;
|
||||||
|
set => Value.Commands = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UnaryCommandAlias() => Value = new UnaryCommand();
|
||||||
|
public UnaryCommandAlias(UnaryCommand value) => Value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class BinaryCommandAlias : ICalcManagerIExprCommandAlias
|
||||||
|
{
|
||||||
|
[JsonIgnore]
|
||||||
|
public BinaryCommand Value;
|
||||||
|
|
||||||
|
[JsonPropertyName("c")]
|
||||||
|
public int Command
|
||||||
|
{
|
||||||
|
get => Value.Command;
|
||||||
|
set => Value.Command = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BinaryCommandAlias() => Value = new BinaryCommand();
|
||||||
|
public BinaryCommandAlias(BinaryCommand value) => Value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class OperandCommandAlias : ICalcManagerIExprCommandAlias
|
||||||
|
{
|
||||||
|
[JsonIgnore]
|
||||||
|
public OperandCommand Value;
|
||||||
|
|
||||||
|
[JsonPropertyName("n")]
|
||||||
|
public bool IsNegative
|
||||||
|
{
|
||||||
|
get => Value.IsNegative;
|
||||||
|
set => Value.IsNegative = value;
|
||||||
|
}
|
||||||
|
[JsonPropertyName("d")]
|
||||||
|
public bool IsDecimalPresent
|
||||||
|
{
|
||||||
|
get => Value.IsDecimalPresent;
|
||||||
|
set => Value.IsDecimalPresent = value;
|
||||||
|
}
|
||||||
|
[JsonPropertyName("s")]
|
||||||
|
public bool IsSciFmt
|
||||||
|
{
|
||||||
|
get => Value.IsSciFmt;
|
||||||
|
set => Value.IsSciFmt = value;
|
||||||
|
}
|
||||||
|
[JsonPropertyName("c")]
|
||||||
|
public IReadOnlyList<int> Commands
|
||||||
|
{
|
||||||
|
get => Value.Commands;
|
||||||
|
set => Value.Commands = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OperandCommandAlias() => Value = new OperandCommand();
|
||||||
|
public OperandCommandAlias(OperandCommand value) => Value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class ParenthesesAlias : ICalcManagerIExprCommandAlias
|
||||||
|
{
|
||||||
|
[JsonIgnore]
|
||||||
|
public Parentheses Value;
|
||||||
|
|
||||||
|
[JsonPropertyName("c")]
|
||||||
|
public int Command
|
||||||
|
{
|
||||||
|
get => Value.Command;
|
||||||
|
set => Value.Command = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ParenthesesAlias() => Value = new Parentheses();
|
||||||
|
public ParenthesesAlias(Parentheses value) => Value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class CalcManagerHistoryItemAlias
|
||||||
|
{
|
||||||
|
[JsonIgnore]
|
||||||
|
public CalcManagerHistoryItem Value;
|
||||||
|
|
||||||
|
[JsonPropertyName("t")]
|
||||||
|
public IEnumerable<CalcManagerTokenAlias> Tokens
|
||||||
|
{
|
||||||
|
get => Value.Tokens.Select(x => new CalcManagerTokenAlias(x));
|
||||||
|
set => Value.Tokens = value.Select(Helpers.MapToken).ToList();
|
||||||
|
}
|
||||||
|
[JsonPropertyName("c")]
|
||||||
|
public IEnumerable<ICalcManagerIExprCommandAlias> Commands
|
||||||
|
{
|
||||||
|
get => Value.Commands.Select(Helpers.MapCommandAlias);
|
||||||
|
set => Value.Commands = value.Select(Helpers.MapCommandAlias).ToList();
|
||||||
|
}
|
||||||
|
[JsonPropertyName("e")]
|
||||||
|
public string Expression
|
||||||
|
{
|
||||||
|
get => Value.Expression;
|
||||||
|
set => Value.Expression = value;
|
||||||
|
}
|
||||||
|
[JsonPropertyName("r")]
|
||||||
|
public string Result
|
||||||
|
{
|
||||||
|
get => Value.Result;
|
||||||
|
set => Value.Result = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CalcManagerHistoryItemAlias() => Value = new CalcManagerHistoryItem();
|
||||||
|
public CalcManagerHistoryItemAlias(CalcManagerHistoryItem value) => Value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class CalcManagerSnapshotAlias
|
||||||
|
{
|
||||||
|
[JsonIgnore]
|
||||||
|
public CalcManagerSnapshot Value;
|
||||||
|
|
||||||
|
[JsonPropertyName("h")]
|
||||||
|
public IEnumerable<CalcManagerHistoryItemAlias> HistoryItems // optional
|
||||||
|
{
|
||||||
|
get => Value.HistoryItems?.Select(x => new CalcManagerHistoryItemAlias { Value = x });
|
||||||
|
set => Value.HistoryItems = value?.Select(x => new CalcManagerHistoryItem
|
||||||
|
{
|
||||||
|
Tokens = x.Tokens.Select(Helpers.MapToken).ToList(),
|
||||||
|
Commands = x.Commands.Select(Helpers.MapCommandAlias).ToList(),
|
||||||
|
Expression = x.Expression,
|
||||||
|
Result = x.Result
|
||||||
|
}).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public CalcManagerSnapshotAlias() => Value = new CalcManagerSnapshot();
|
||||||
|
public CalcManagerSnapshotAlias(CalcManagerSnapshot value) => Value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class PrimaryDisplaySnapshotAlias
|
||||||
|
{
|
||||||
|
[JsonIgnore]
|
||||||
|
public PrimaryDisplaySnapshot Value;
|
||||||
|
|
||||||
|
[JsonPropertyName("d")]
|
||||||
|
public string DisplayValue
|
||||||
|
{
|
||||||
|
get => Value.DisplayValue;
|
||||||
|
set => Value.DisplayValue = value;
|
||||||
|
}
|
||||||
|
[JsonPropertyName("e")]
|
||||||
|
public bool IsError
|
||||||
|
{
|
||||||
|
get => Value.IsError;
|
||||||
|
set => Value.IsError = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PrimaryDisplaySnapshotAlias() => Value = new PrimaryDisplaySnapshot();
|
||||||
|
public PrimaryDisplaySnapshotAlias(PrimaryDisplaySnapshot value) => Value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class ExpressionDisplaySnapshotAlias
|
||||||
|
{
|
||||||
|
[JsonIgnore]
|
||||||
|
public ExpressionDisplaySnapshot Value;
|
||||||
|
|
||||||
|
[JsonPropertyName("t")]
|
||||||
|
public IEnumerable<CalcManagerTokenAlias> Tokens
|
||||||
|
{
|
||||||
|
get => Value.Tokens.Select(x => new CalcManagerTokenAlias(x));
|
||||||
|
set => Value.Tokens = value.Select(Helpers.MapToken).ToList();
|
||||||
|
}
|
||||||
|
[JsonPropertyName("c")]
|
||||||
|
public IEnumerable<ICalcManagerIExprCommandAlias> Commands
|
||||||
|
{
|
||||||
|
get => Value.Commands.Select(Helpers.MapCommandAlias);
|
||||||
|
set => Value.Commands = value.Select(Helpers.MapCommandAlias).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExpressionDisplaySnapshotAlias() => Value = new ExpressionDisplaySnapshot();
|
||||||
|
public ExpressionDisplaySnapshotAlias(ExpressionDisplaySnapshot value) => Value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class StandardCalculatorSnapshotAlias
|
||||||
|
{
|
||||||
|
[JsonIgnore]
|
||||||
|
public StandardCalculatorSnapshot Value;
|
||||||
|
|
||||||
|
[JsonPropertyName("m")]
|
||||||
|
public CalcManagerSnapshotAlias CalcManager
|
||||||
|
{
|
||||||
|
get => new CalcManagerSnapshotAlias(Value.CalcManager);
|
||||||
|
set => Value.CalcManager = value.Value;
|
||||||
|
}
|
||||||
|
[JsonPropertyName("p")]
|
||||||
|
public PrimaryDisplaySnapshotAlias PrimaryDisplay
|
||||||
|
{
|
||||||
|
get => new PrimaryDisplaySnapshotAlias(Value.PrimaryDisplay);
|
||||||
|
set => Value.PrimaryDisplay = value.Value;
|
||||||
|
}
|
||||||
|
[JsonPropertyName("e")]
|
||||||
|
public ExpressionDisplaySnapshotAlias ExpressionDisplay // optional
|
||||||
|
{
|
||||||
|
get => Value.ExpressionDisplay != null ? new ExpressionDisplaySnapshotAlias(Value.ExpressionDisplay) : null;
|
||||||
|
set => Value.ExpressionDisplay = value?.Value;
|
||||||
|
}
|
||||||
|
[JsonPropertyName("c")]
|
||||||
|
public IEnumerable<ICalcManagerIExprCommandAlias> Commands
|
||||||
|
{
|
||||||
|
get => Value.DisplayCommands.Select(Helpers.MapCommandAlias);
|
||||||
|
set => Value.DisplayCommands = value.Select(Helpers.MapCommandAlias).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public StandardCalculatorSnapshotAlias() => Value = new StandardCalculatorSnapshot();
|
||||||
|
public StandardCalculatorSnapshotAlias(StandardCalculatorSnapshot value) => Value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class ApplicationSnapshotAlias
|
||||||
|
{
|
||||||
|
[JsonIgnore]
|
||||||
|
public ApplicationSnapshot Value;
|
||||||
|
|
||||||
|
[JsonPropertyName("m")]
|
||||||
|
public int Mode { get => Value.Mode; set => Value.Mode = value; }
|
||||||
|
[JsonPropertyName("s")]
|
||||||
|
public StandardCalculatorSnapshotAlias StandardCalculatorSnapshot // optional
|
||||||
|
{
|
||||||
|
get => Value.StandardCalculator != null ? new StandardCalculatorSnapshotAlias(Value.StandardCalculator) : null;
|
||||||
|
set => Value.StandardCalculator = value?.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ApplicationSnapshotAlias() => Value = new ApplicationSnapshot();
|
||||||
|
public ApplicationSnapshotAlias(ApplicationSnapshot value) => Value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static class Helpers
|
||||||
|
{
|
||||||
|
public static CalcManagerToken MapToken(CalcManagerTokenAlias token)
|
||||||
|
{
|
||||||
|
return new CalcManagerToken { OpCodeName = token.OpCodeName, CommandIndex = token.CommandIndex };
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ICalcManagerIExprCommandAlias MapCommandAlias(ICalcManagerIExprCommand exprCmd)
|
||||||
|
{
|
||||||
|
if (exprCmd is UnaryCommand unary)
|
||||||
|
{
|
||||||
|
return new UnaryCommandAlias(unary);
|
||||||
|
}
|
||||||
|
else if (exprCmd is BinaryCommand binary)
|
||||||
|
{
|
||||||
|
return new BinaryCommandAlias(binary);
|
||||||
|
}
|
||||||
|
else if (exprCmd is OperandCommand operand)
|
||||||
|
{
|
||||||
|
return new OperandCommandAlias(operand);
|
||||||
|
}
|
||||||
|
else if (exprCmd is Parentheses paren)
|
||||||
|
{
|
||||||
|
return new ParenthesesAlias(paren);
|
||||||
|
}
|
||||||
|
throw new NotImplementedException("unhandled command type.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ICalcManagerIExprCommand MapCommandAlias(ICalcManagerIExprCommandAlias exprCmd)
|
||||||
|
{
|
||||||
|
if (exprCmd is UnaryCommandAlias unary)
|
||||||
|
{
|
||||||
|
return new UnaryCommand { Commands = unary.Commands };
|
||||||
|
}
|
||||||
|
else if (exprCmd is BinaryCommandAlias binary)
|
||||||
|
{
|
||||||
|
return new BinaryCommand { Command = binary.Command };
|
||||||
|
}
|
||||||
|
else if (exprCmd is OperandCommandAlias operand)
|
||||||
|
{
|
||||||
|
return new OperandCommand
|
||||||
|
{
|
||||||
|
IsNegative = operand.IsNegative,
|
||||||
|
IsDecimalPresent = operand.IsDecimalPresent,
|
||||||
|
IsSciFmt = operand.IsSciFmt,
|
||||||
|
Commands = operand.Commands
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else if (exprCmd is ParenthesesAlias paren)
|
||||||
|
{
|
||||||
|
return new Parentheses { Command = paren.Command };
|
||||||
|
}
|
||||||
|
throw new NotImplementedException("unhandled command type.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -245,6 +245,7 @@ namespace CalculatorApp
|
||||||
HistoryFlyout.FlyoutPresenterStyle.Setters.Add(new Setter(AutomationProperties.NameProperty, historyPaneName));
|
HistoryFlyout.FlyoutPresenterStyle.Setters.Add(new Setter(AutomationProperties.NameProperty, historyPaneName));
|
||||||
string memoryPaneName = AppResourceProvider.GetInstance().GetResourceString("MemoryPane");
|
string memoryPaneName = AppResourceProvider.GetInstance().GetResourceString("MemoryPane");
|
||||||
MemoryFlyout.FlyoutPresenterStyle.Setters.Add(new Setter(AutomationProperties.NameProperty, memoryPaneName));
|
MemoryFlyout.FlyoutPresenterStyle.Setters.Add(new Setter(AutomationProperties.NameProperty, memoryPaneName));
|
||||||
|
OnIsInErrorPropertyChanged();
|
||||||
|
|
||||||
// Delay load things later when we get a chance.
|
// Delay load things later when we get a chance.
|
||||||
WeakReference weakThis = new WeakReference(this);
|
WeakReference weakThis = new WeakReference(this);
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
|
using System.Text.Json;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
using Windows.ApplicationModel.UserActivities;
|
using Windows.ApplicationModel.UserActivities;
|
||||||
using Windows.Data.Json;
|
|
||||||
using Windows.Foundation;
|
using Windows.Foundation;
|
||||||
using Windows.Graphics.Display;
|
using Windows.Graphics.Display;
|
||||||
using Windows.Storage;
|
using Windows.Storage;
|
||||||
|
@ -18,6 +18,7 @@ using Microsoft.UI.Xaml.Controls;
|
||||||
|
|
||||||
using CalculatorApp.Common;
|
using CalculatorApp.Common;
|
||||||
using CalculatorApp.Converters;
|
using CalculatorApp.Converters;
|
||||||
|
using CalculatorApp.JsonUtils;
|
||||||
using CalculatorApp.ViewModel;
|
using CalculatorApp.ViewModel;
|
||||||
using CalculatorApp.ViewModel.Common;
|
using CalculatorApp.ViewModel.Common;
|
||||||
using CalculatorApp.ViewModel.Common.Automation;
|
using CalculatorApp.ViewModel.Common.Automation;
|
||||||
|
@ -61,16 +62,29 @@ namespace CalculatorApp
|
||||||
|
|
||||||
UserActivityRequestManager.GetForCurrentView().UserActivityRequested += async (_, args) =>
|
UserActivityRequestManager.GetForCurrentView().UserActivityRequested += async (_, args) =>
|
||||||
{
|
{
|
||||||
var deferral = args.GetDeferral();
|
using (var deferral = args.GetDeferral())
|
||||||
|
{
|
||||||
if (deferral == null)
|
if (deferral == null)
|
||||||
{
|
{
|
||||||
// Windows Bug in ni_moment won't return the deferral propoerly, see https://microsoft.visualstudio.com/DefaultCollection/OS/_workitems/edit/47775705/
|
// FIXME: https://microsoft.visualstudio.com/DefaultCollection/OS/_workitems/edit/47775705/
|
||||||
|
TraceLogger.GetInstance().LogRecallError("55e29ba5-6097-40ec-8960-458750be3039");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var channel = UserActivityChannel.GetDefault();
|
var channel = UserActivityChannel.GetDefault();
|
||||||
var activity = await channel.GetOrCreateUserActivityAsync($"{Guid.NewGuid()}");
|
var activity = await channel.GetOrCreateUserActivityAsync($"{Guid.NewGuid()}");
|
||||||
activity.ActivationUri = new Uri($"ms-calculator:snapshots/{activity.ActivityId}");
|
string embeddedData;
|
||||||
activity.ContentInfo = UserActivityContentInfo.FromJson(Model.SaveApplicationSnapshot().Stringify());
|
try
|
||||||
|
{
|
||||||
|
var json = JsonSerializer.Serialize(new ApplicationSnapshotAlias(Model.Snapshot));
|
||||||
|
embeddedData = Convert.ToBase64String(DeflateUtils.Compress(json));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
TraceLogger.GetInstance().LogRecallError($"Error occurs during the serialization of Snapshot. Exception: {ex}");
|
||||||
|
deferral.Complete();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
activity.ActivationUri = new Uri($"ms-calculator:snapshot/{embeddedData}");
|
||||||
activity.IsRoamable = false;
|
activity.IsRoamable = false;
|
||||||
var resProvider = AppResourceProvider.GetInstance();
|
var resProvider = AppResourceProvider.GetInstance();
|
||||||
activity.VisualElements.DisplayText =
|
activity.VisualElements.DisplayText =
|
||||||
|
@ -79,6 +93,7 @@ namespace CalculatorApp
|
||||||
args.Request.SetUserActivity(activity);
|
args.Request.SetUserActivity(activity);
|
||||||
deferral.Complete();
|
deferral.Complete();
|
||||||
TraceLogger.GetInstance().LogRecallSnapshot(Model.Mode);
|
TraceLogger.GetInstance().LogRecallSnapshot(Model.Mode);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,22 +180,18 @@ namespace CalculatorApp
|
||||||
}
|
}
|
||||||
else if (e.Parameter is SnapshotLaunchArguments snapshotArgs)
|
else if (e.Parameter is SnapshotLaunchArguments snapshotArgs)
|
||||||
{
|
{
|
||||||
_ = Window.Current.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
|
Model.Initialize(initialMode);
|
||||||
|
if (!snapshotArgs.HasError)
|
||||||
{
|
{
|
||||||
var channel = UserActivityChannel.GetDefault();
|
Model.RestoreFromSnapshot(snapshotArgs.Snapshot);
|
||||||
var activity = await channel.GetOrCreateUserActivityAsync(snapshotArgs.ActivityId);
|
TraceLogger.GetInstance().LogRecallRestore((ViewMode)snapshotArgs.Snapshot.Mode);
|
||||||
|
|
||||||
if (TryRestoreFromActivity(snapshotArgs, activity, out var errorMessage))
|
|
||||||
{
|
|
||||||
TraceLogger.GetInstance().LogRecallRestore(Model.Mode);
|
|
||||||
SelectNavigationItemByModel();
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
TraceLogger.GetInstance().LogRecallError(Model.Mode, errorMessage);
|
_ = Window.Current.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
|
||||||
|
async () => await ShowSnapshotLaunchErrorAsync());
|
||||||
|
TraceLogger.GetInstance().LogRecallError("OnNavigatedTo:Found errors.");
|
||||||
}
|
}
|
||||||
});
|
|
||||||
Model.Initialize(initialMode);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -188,38 +199,6 @@ namespace CalculatorApp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool TryRestoreFromActivity(SnapshotLaunchArguments snapshotArgs, UserActivity activity, out string errorMessage)
|
|
||||||
{
|
|
||||||
if (!snapshotArgs.VerifyIncomingActivity(activity))
|
|
||||||
{
|
|
||||||
errorMessage = "IncomingActivityFailed";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Work around for bug https://microsoft.visualstudio.com/DefaultCollection/OS/_workitems/edit/48931227
|
|
||||||
// where ContentInfo can't be directly accessed.
|
|
||||||
if (!JsonObject.TryParse(activity.ToJson(), out var activityJson))
|
|
||||||
{
|
|
||||||
errorMessage = "ParseJsonError";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!activityJson.ContainsKey("contentInfo"))
|
|
||||||
{
|
|
||||||
errorMessage = "ContentInfoNotExist";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Model.TryRestoreFromSnapshot(activityJson.GetNamedObject("contentInfo")))
|
|
||||||
{
|
|
||||||
errorMessage = "RestoreFromSnapshotFailed";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
errorMessage = string.Empty;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void InitializeNavViewCategoriesSource()
|
private void InitializeNavViewCategoriesSource()
|
||||||
{
|
{
|
||||||
NavViewCategoriesSource = ExpandNavViewCategoryGroups(Model.Categories);
|
NavViewCategoriesSource = ExpandNavViewCategoryGroups(Model.Categories);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue