Merge master into feature/GraphingCalculator branch (#585)

* Merge master into feature/GraphingCalculator branch
This commit is contained in:
Stephanie Anderl
2019-07-15 11:17:21 -07:00
committed by GitHub
parent 1475b49120
commit a418777f02
447 changed files with 18056 additions and 19323 deletions

View File

@@ -46,21 +46,16 @@ static constexpr auto CACHE_LANGCODE_KEY = L"CURRENCY_CONVERTER_LANGCODE";
static constexpr auto CACHE_DELIMITER = L"%";
static constexpr auto STATIC_DATA_FILENAME = L"CURRENCY_CONVERTER_STATIC_DATA.txt";
static constexpr array<wstring_view, 5> STATIC_DATA_PROPERTIES = {
wstring_view{ L"CountryCode", 11 },
wstring_view{ L"CountryName", 11 },
wstring_view{ L"CurrencyCode", 12 },
wstring_view{ L"CurrencyName", 12 },
wstring_view{ L"CurrencySymbol", 14 }
};
static constexpr array<wstring_view, 5> STATIC_DATA_PROPERTIES = { wstring_view{ L"CountryCode", 11 },
wstring_view{ L"CountryName", 11 },
wstring_view{ L"CurrencyCode", 12 },
wstring_view{ L"CurrencyName", 12 },
wstring_view{ L"CurrencySymbol", 14 } };
static constexpr auto ALL_RATIOS_DATA_FILENAME = L"CURRENCY_CONVERTER_ALL_RATIOS_DATA.txt";
static constexpr auto RATIO_KEY = L"Rt";
static constexpr auto CURRENCY_CODE_KEY = L"An";
static constexpr array<wstring_view, 2> ALL_RATIOS_DATA_PROPERTIES = {
wstring_view{ RATIO_KEY, 2 },
wstring_view{ CURRENCY_CODE_KEY, 2 }
};
static constexpr array<wstring_view, 2> ALL_RATIOS_DATA_PROPERTIES = { wstring_view{ RATIO_KEY, 2 }, wstring_view{ CURRENCY_CODE_KEY, 2 } };
static constexpr auto DEFAULT_FROM_TO_CURRENCY_FILE_URI = L"ms-appx:///DataLoaders/DefaultFromToCurrency.json";
static constexpr auto FROM_KEY = L"from";
@@ -92,18 +87,29 @@ namespace CalculatorApp
}
}
CurrencyDataLoader::CurrencyDataLoader(_In_ unique_ptr<ICurrencyHttpClient> client) :
m_client(move(client)),
m_loadStatus(CurrencyLoadStatus::NotLoaded),
m_responseLanguage(L"en-US"),
m_ratioFormat(L""),
m_timestampFormat(L""),
m_networkManager(ref new NetworkManager()),
m_meteredOverrideSet(false)
CurrencyDataLoader::CurrencyDataLoader(_In_ unique_ptr<ICurrencyHttpClient> client, const wchar_t * forcedResponseLanguage)
: m_client(move(client))
, m_loadStatus(CurrencyLoadStatus::NotLoaded)
, m_responseLanguage(L"en-US")
, m_ratioFormat(L"")
, m_timestampFormat(L"")
, m_networkManager(ref new NetworkManager())
, m_meteredOverrideSet(false)
{
if (GlobalizationPreferences::Languages->Size > 0)
if (forcedResponseLanguage != nullptr)
{
m_responseLanguage = GlobalizationPreferences::Languages->GetAt(0);
m_responseLanguage = ref new Platform::String(forcedResponseLanguage);
}
else
{
if (GlobalizationPreferences::Languages->Size > 0)
{
m_responseLanguage = GlobalizationPreferences::Languages->GetAt(0);
}
else
{
m_responseLanguage = L"en-US";
}
}
if (m_client != nullptr)
@@ -112,13 +118,14 @@ CurrencyDataLoader::CurrencyDataLoader(_In_ unique_ptr<ICurrencyHttpClient> clie
m_client->SetResponseLanguage(m_responseLanguage);
}
auto localizationService = LocalizationService::GetInstance();
if (CoreWindow::GetForCurrentThread() != nullptr)
{
// Must have a CoreWindow to access the resource context.
m_isRtlLanguage = LocalizationService::GetInstance()->IsRtlLayout();
m_isRtlLanguage = localizationService->IsRtlLayout();
}
m_ratioFormatter = LocalizationService::GetRegionalSettingsAwareDecimalFormatter();
m_ratioFormatter = localizationService->GetRegionalSettingsAwareDecimalFormatter();
m_ratioFormatter->IsGrouped = true;
m_ratioFormatter->IsDecimalPointAlwaysDisplayed = true;
m_ratioFormatter->FractionDigits = FORMATTER_DIGIT_COUNT;
@@ -141,11 +148,8 @@ void CurrencyDataLoader::RegisterForNetworkBehaviorChanges()
{
UnregisterForNetworkBehaviorChanges();
m_networkBehaviorToken =
m_networkManager->NetworkBehaviorChanged += ref new NetworkBehaviorChangedHandler([this](NetworkAccessBehavior newBehavior)
{
this->OnNetworkBehaviorChanged(newBehavior);
});
m_networkBehaviorToken = m_networkManager->NetworkBehaviorChanged +=
ref new NetworkBehaviorChangedHandler([this](NetworkAccessBehavior newBehavior) { this->OnNetworkBehaviorChanged(newBehavior); });
OnNetworkBehaviorChanged(NetworkManager::GetNetworkAccessBehavior());
}
@@ -186,9 +190,8 @@ void CurrencyDataLoader::LoadData()
if (!LoadFinished())
{
create_task([this]() -> task<bool>
{
vector<function<task<bool>()>> loadFunctions = {
create_task([this]() -> task<bool> {
vector<function<future<bool>()>> loadFunctions = {
[this]() { return TryLoadDataFromCacheAsync(); },
[this]() { return TryLoadDataFromWebAsync(); },
};
@@ -204,11 +207,13 @@ void CurrencyDataLoader::LoadData()
}
co_return didLoad;
}).then([this](bool didLoad)
{
UpdateDisplayedTimestamp();
NotifyDataLoadFinished(didLoad);
}, task_continuation_context::use_current());
})
.then(
[this](bool didLoad) {
UpdateDisplayedTimestamp();
NotifyDataLoadFinished(didLoad);
},
task_continuation_context::use_current());
}
};
#pragma optimize("", on)
@@ -285,32 +290,24 @@ pair<wstring, wstring> CurrencyDataLoader::GetCurrencyRatioEquality(_In_ const U
wstring roundedFormat = m_ratioFormatter->Format(rounded)->Data();
wstring ratioString = LocalizationStringUtil::GetLocalizedString(
m_ratioFormat.c_str(),
digitSymbol.c_str(),
unit1.abbreviation.c_str(),
roundedFormat.c_str(),
unit2.abbreviation.c_str()
);
m_ratioFormat.c_str(), digitSymbol.c_str(), unit1.abbreviation.c_str(), roundedFormat.c_str(), unit2.abbreviation.c_str());
wstring accessibleRatioString = LocalizationStringUtil::GetLocalizedString(
m_ratioFormat.c_str(),
digitSymbol.c_str(),
unit1.accessibleName.c_str(),
roundedFormat.c_str(),
unit2.accessibleName.c_str()
);
m_ratioFormat.c_str(), digitSymbol.c_str(), unit1.accessibleName.c_str(), roundedFormat.c_str(), unit2.accessibleName.c_str());
return make_pair(ratioString, accessibleRatioString);
}
}
}
catch (...) {}
catch (...)
{
}
return make_pair(L"", L"");
}
#pragma optimize("", off) // Turn off optimizations to work around DevDiv 393321
task<bool> CurrencyDataLoader::TryLoadDataFromCacheAsync()
future<bool> CurrencyDataLoader::TryLoadDataFromCacheAsync()
{
try
{
@@ -324,8 +321,7 @@ task<bool> CurrencyDataLoader::TryLoadDataFromCacheAsync()
bool loadComplete = false;
m_cacheTimestamp = static_cast<DateTime>(localSettings->Values->Lookup(CacheTimestampKey));
if (Utils::IsDateTimeOlderThan(m_cacheTimestamp, DAY_DURATION)
&& m_networkAccessBehavior == NetworkAccessBehavior::Normal)
if (Utils::IsDateTimeOlderThan(m_cacheTimestamp, DAY_DURATION) && m_networkAccessBehavior == NetworkAccessBehavior::Normal)
{
loadComplete = co_await TryLoadDataFromWebAsync();
}
@@ -337,7 +333,7 @@ task<bool> CurrencyDataLoader::TryLoadDataFromCacheAsync()
co_return loadComplete;
}
catch (Exception^ ex)
catch (Exception ^ ex)
{
TraceLogger::GetInstance().LogPlatformException(__FUNCTIONW__, ex);
co_return false;
@@ -353,7 +349,7 @@ task<bool> CurrencyDataLoader::TryLoadDataFromCacheAsync()
}
}
task<bool> CurrencyDataLoader::TryFinishLoadFromCacheAsync()
future<bool> CurrencyDataLoader::TryFinishLoadFromCacheAsync()
{
auto localSettings = ApplicationData::Current->LocalSettings;
if (localSettings == nullptr)
@@ -361,29 +357,24 @@ task<bool> CurrencyDataLoader::TryFinishLoadFromCacheAsync()
co_return false;
}
if (!localSettings->Values->HasKey(CacheLangcodeKey)
|| !static_cast<String^>(localSettings->Values->Lookup(CacheLangcodeKey))->Equals(m_responseLanguage))
if (!localSettings->Values->HasKey(CacheLangcodeKey) || !static_cast<String ^>(localSettings->Values->Lookup(CacheLangcodeKey))->Equals(m_responseLanguage))
{
co_return false;
}
StorageFolder^ localCacheFolder = ApplicationData::Current->LocalCacheFolder;
StorageFolder ^ localCacheFolder = ApplicationData::Current->LocalCacheFolder;
if (localCacheFolder == nullptr)
{
co_return false;
}
String^ staticDataResponse = co_await Utils::ReadFileFromFolder(localCacheFolder, StaticDataFilename);
String^ allRatiosResponse = co_await Utils::ReadFileFromFolder(localCacheFolder, AllRatiosDataFilename);
String ^ staticDataResponse = co_await Utils::ReadFileFromFolder(localCacheFolder, StaticDataFilename);
String ^ allRatiosResponse = co_await Utils::ReadFileFromFolder(localCacheFolder, AllRatiosDataFilename);
vector<UCM::CurrencyStaticData> staticData{};
CurrencyRatioMap ratioMap{};
bool didParse = TryParseWebResponses(
staticDataResponse,
allRatiosResponse,
staticData,
ratioMap);
bool didParse = TryParseWebResponses(staticDataResponse, allRatiosResponse, staticData, ratioMap);
if (!didParse)
{
co_return false;
@@ -395,7 +386,7 @@ task<bool> CurrencyDataLoader::TryFinishLoadFromCacheAsync()
co_return true;
}
task<bool> CurrencyDataLoader::TryLoadDataFromWebAsync()
future<bool> CurrencyDataLoader::TryLoadDataFromWebAsync()
{
try
{
@@ -406,14 +397,13 @@ task<bool> CurrencyDataLoader::TryLoadDataFromWebAsync()
co_return false;
}
if (m_networkAccessBehavior == NetworkAccessBehavior::Offline ||
(m_networkAccessBehavior == NetworkAccessBehavior::OptIn && !m_meteredOverrideSet))
if (m_networkAccessBehavior == NetworkAccessBehavior::Offline || (m_networkAccessBehavior == NetworkAccessBehavior::OptIn && !m_meteredOverrideSet))
{
co_return false;
}
String^ staticDataResponse = co_await m_client->GetCurrencyMetadata();
String^ allRatiosResponse = co_await m_client->GetCurrencyRatios();
String ^ staticDataResponse = co_await m_client->GetCurrencyMetadata();
String ^ allRatiosResponse = co_await m_client->GetCurrencyRatios();
if (staticDataResponse == nullptr || allRatiosResponse == nullptr)
{
co_return false;
@@ -422,11 +412,7 @@ task<bool> CurrencyDataLoader::TryLoadDataFromWebAsync()
vector<UCM::CurrencyStaticData> staticData{};
CurrencyRatioMap ratioMap{};
bool didParse = TryParseWebResponses(
staticDataResponse,
allRatiosResponse,
staticData,
ratioMap);
bool didParse = TryParseWebResponses(staticDataResponse, allRatiosResponse, staticData, ratioMap);
if (!didParse)
{
co_return false;
@@ -437,19 +423,12 @@ task<bool> CurrencyDataLoader::TryLoadDataFromWebAsync()
try
{
const vector<pair<String^, String^>> cachedFiles = {
{ StaticDataFilename, staticDataResponse },
{ AllRatiosDataFilename, allRatiosResponse }
};
const vector<pair<String ^, String ^>> cachedFiles = { { StaticDataFilename, staticDataResponse }, { AllRatiosDataFilename, allRatiosResponse } };
StorageFolder^ localCacheFolder = ApplicationData::Current->LocalCacheFolder;
StorageFolder ^ localCacheFolder = ApplicationData::Current->LocalCacheFolder;
for (const auto& fileInfo : cachedFiles)
{
co_await Utils::WriteFileToFolder(
localCacheFolder,
fileInfo.first,
fileInfo.second,
CreationCollisionOption::ReplaceExisting);
co_await Utils::WriteFileToFolder(localCacheFolder, fileInfo.first, fileInfo.second, CreationCollisionOption::ReplaceExisting);
}
SaveLangCodeAndTimestamp();
@@ -464,7 +443,7 @@ task<bool> CurrencyDataLoader::TryLoadDataFromWebAsync()
co_return true;
}
catch (Exception^ ex)
catch (Exception ^ ex)
{
TraceLogger::GetInstance().LogPlatformException(__FUNCTIONW__, ex);
co_return false;
@@ -480,7 +459,7 @@ task<bool> CurrencyDataLoader::TryLoadDataFromWebAsync()
}
}
task<bool> CurrencyDataLoader::TryLoadDataFromWebOverrideAsync()
future<bool> CurrencyDataLoader::TryLoadDataFromWebOverrideAsync()
{
m_meteredOverrideSet = true;
bool didLoad = co_await TryLoadDataFromWebAsync();
@@ -495,18 +474,17 @@ task<bool> CurrencyDataLoader::TryLoadDataFromWebOverrideAsync()
#pragma optimize("", on)
bool CurrencyDataLoader::TryParseWebResponses(
_In_ String^ staticDataJson,
_In_ String^ allRatiosJson,
_In_ String ^ staticDataJson,
_In_ String ^ allRatiosJson,
_Inout_ vector<UCM::CurrencyStaticData>& staticData,
_Inout_ CurrencyRatioMap& allRatiosData)
{
return TryParseStaticData(staticDataJson, staticData)
&& TryParseAllRatiosData(allRatiosJson, allRatiosData);
return TryParseStaticData(staticDataJson, staticData) && TryParseAllRatiosData(allRatiosJson, allRatiosData);
}
bool CurrencyDataLoader::TryParseStaticData(_In_ String^ rawJson, _Inout_ vector<UCM::CurrencyStaticData>& staticData)
bool CurrencyDataLoader::TryParseStaticData(_In_ String ^ rawJson, _Inout_ vector<UCM::CurrencyStaticData>& staticData)
{
JsonArray^ data = nullptr;
JsonArray ^ data = nullptr;
if (!JsonArray::TryParse(rawJson, &data))
{
return false;
@@ -518,46 +496,46 @@ bool CurrencyDataLoader::TryParseStaticData(_In_ String^ rawJson, _Inout_ vector
wstring currencyName{ L"" };
wstring currencySymbol{ L"" };
vector<wstring*> values = {
&countryCode,
&countryName,
&currencyCode,
&currencyName,
&currencySymbol
};
vector<wstring*> values = { &countryCode, &countryName, &currencyCode, &currencyName, &currencySymbol };
assert(values.size() == STATIC_DATA_PROPERTIES.size());
staticData.resize(size_t{ data->Size });
for (unsigned int i = 0; i < data->Size; i++)
{
JsonObject^ obj = data->GetAt(i)->GetObject();
JsonObject ^ obj;
try
{
obj = data->GetAt(i)->GetObject();
}
catch (COMException ^ e)
{
if (e->HResult == E_ILLEGAL_METHOD_CALL)
{
continue;
}
else
{
throw;
}
}
for (size_t j = 0; j < values.size(); j++)
{
(*values[j]) = obj->GetNamedString(StringReference(STATIC_DATA_PROPERTIES[j].data()))->Data();
}
staticData[i] = CurrencyStaticData{
countryCode,
countryName,
currencyCode,
currencyName,
currencySymbol
};
staticData[i] = CurrencyStaticData{ countryCode, countryName, currencyCode, currencyName, currencySymbol };
}
// TODO - MSFT 8533667: this sort will be replaced by a WinRT call to sort localized strings
sort(begin(staticData), end(staticData), [](CurrencyStaticData unit1, CurrencyStaticData unit2)
{
return unit1.countryName < unit2.countryName;
});
sort(begin(staticData), end(staticData), [](CurrencyStaticData unit1, CurrencyStaticData unit2) { return unit1.countryName < unit2.countryName; });
return true;
}
bool CurrencyDataLoader::TryParseAllRatiosData(_In_ String^ rawJson, _Inout_ CurrencyRatioMap& allRatios)
bool CurrencyDataLoader::TryParseAllRatiosData(_In_ String ^ rawJson, _Inout_ CurrencyRatioMap& allRatios)
{
JsonArray^ data = nullptr;
JsonArray ^ data = nullptr;
if (!JsonArray::TryParse(rawJson, &data))
{
return false;
@@ -568,17 +546,28 @@ bool CurrencyDataLoader::TryParseAllRatiosData(_In_ String^ rawJson, _Inout_ Cur
allRatios.clear();
for (unsigned int i = 0; i < data->Size; i++)
{
JsonObject^ obj = data->GetAt(i)->GetObject();
JsonObject ^ obj;
try
{
obj = data->GetAt(i)->GetObject();
}
catch (COMException^ e)
{
if (e->HResult == E_ILLEGAL_METHOD_CALL)
{
continue;
}
else
{
throw;
}
}
// Rt is ratio, An is target currency ISO code.
double relativeRatio = obj->GetNamedNumber(StringReference(RATIO_KEY));
wstring targetCurrencyCode = obj->GetNamedString(StringReference(CURRENCY_CODE_KEY))->Data();
allRatios.emplace(targetCurrencyCode, CurrencyRatio{
relativeRatio,
sourceCurrencyCode,
targetCurrencyCode
});
allRatios.emplace(targetCurrencyCode, CurrencyRatio{ relativeRatio, sourceCurrencyCode, targetCurrencyCode });
}
return true;
@@ -685,6 +674,23 @@ void CurrencyDataLoader::GuaranteeSelectedUnits()
isConversionTargetSet = true;
}
}
// If still not set for either source or target, just select the first currency in the list
if (!m_currencyUnits.empty())
{
if (!isConversionSourceSet)
{
m_currencyUnits[0].isConversionSource = true;
isConversionSourceSet = true;
}
if (!isConversionTargetSet)
{
m_currencyUnits[0].isConversionTarget = true;
isConversionTargetSet = true;
}
}
}
void CurrencyDataLoader::NotifyDataLoadFinished(bool didLoad)
@@ -702,7 +708,7 @@ void CurrencyDataLoader::NotifyDataLoadFinished(bool didLoad)
void CurrencyDataLoader::SaveLangCodeAndTimestamp()
{
ApplicationDataContainer^ localSettings = ApplicationData::Current->LocalSettings;
ApplicationDataContainer ^ localSettings = ApplicationData::Current->LocalSettings;
if (localSettings == nullptr)
{
return;
@@ -729,17 +735,13 @@ wstring CurrencyDataLoader::GetCurrencyTimestamp()
DateTime epoch{};
if (m_cacheTimestamp.UniversalTime != epoch.UniversalTime)
{
DateTimeFormatter^ dateFormatter = ref new DateTimeFormatter(L"{month.abbreviated} {day.integer}, {year.full}");
DateTimeFormatter ^ dateFormatter = ref new DateTimeFormatter(L"{month.abbreviated} {day.integer}, {year.full}");
wstring date = dateFormatter->Format(m_cacheTimestamp)->Data();
DateTimeFormatter^ timeFormatter = ref new DateTimeFormatter(L"shorttime");
DateTimeFormatter ^ timeFormatter = ref new DateTimeFormatter(L"shorttime");
wstring time = timeFormatter->Format(m_cacheTimestamp)->Data();
timestamp = LocalizationStringUtil::GetLocalizedString(
m_timestampFormat.c_str(),
date.c_str(),
time.c_str()
);
timestamp = LocalizationStringUtil::GetLocalizedString(m_timestampFormat.c_str(), date.c_str(), time.c_str());
}
return timestamp;
@@ -758,23 +760,25 @@ task<SelectedUnits> CurrencyDataLoader::GetDefaultFromToCurrency()
try
{
// Second, see if the current locale has preset defaults in DefaultFromToCurrency.json.
Uri^ fileUri = ref new Uri(StringReference(DEFAULT_FROM_TO_CURRENCY_FILE_URI));
StorageFile^ defaultFromToCurrencyFile = co_await StorageFile::GetFileFromApplicationUriAsync(fileUri);
Uri ^ fileUri = ref new Uri(StringReference(DEFAULT_FROM_TO_CURRENCY_FILE_URI));
StorageFile ^ defaultFromToCurrencyFile = co_await StorageFile::GetFileFromApplicationUriAsync(fileUri);
if (defaultFromToCurrencyFile != nullptr)
{
String^ fileContents = co_await FileIO::ReadTextAsync(defaultFromToCurrencyFile);
JsonObject^ fromToObject = JsonObject::Parse(fileContents);
JsonObject^ regionalDefaults = fromToObject->GetNamedObject(m_responseLanguage);
String ^ fileContents = co_await FileIO::ReadTextAsync(defaultFromToCurrencyFile);
JsonObject ^ fromToObject = JsonObject::Parse(fileContents);
JsonObject ^ regionalDefaults = fromToObject->GetNamedObject(m_responseLanguage);
// Get both values before assignment in-case either fails.
String^ selectedFrom = regionalDefaults->GetNamedString(StringReference(FROM_KEY));
String^ selectedTo = regionalDefaults->GetNamedString(StringReference(TO_KEY));
String ^ selectedFrom = regionalDefaults->GetNamedString(StringReference(FROM_KEY));
String ^ selectedTo = regionalDefaults->GetNamedString(StringReference(TO_KEY));
fromCurrency = selectedFrom->Data();
toCurrency = selectedTo->Data();
}
}
catch (...) {}
catch (...)
{
}
}
co_return make_pair(fromCurrency, toCurrency);
@@ -783,16 +787,16 @@ task<SelectedUnits> CurrencyDataLoader::GetDefaultFromToCurrency()
bool CurrencyDataLoader::TryGetLastUsedCurrenciesFromLocalSettings(_Out_ wstring* const fromCurrency, _Out_ wstring* const toCurrency)
{
String^ fromKey = UnitConverterResourceKeys::CurrencyUnitFromKey;
String^ toKey = UnitConverterResourceKeys::CurrencyUnitToKey;
ApplicationDataContainer^ localSettings = ApplicationData::Current->LocalSettings;
String ^ fromKey = UnitConverterResourceKeys::CurrencyUnitFromKey;
String ^ toKey = UnitConverterResourceKeys::CurrencyUnitToKey;
ApplicationDataContainer ^ localSettings = ApplicationData::Current->LocalSettings;
if (localSettings != nullptr && localSettings->Values != nullptr)
{
IPropertySet^ values = localSettings->Values;
IPropertySet ^ values = localSettings->Values;
if (values->HasKey(fromKey) && values->HasKey(toKey))
{
*fromCurrency = static_cast<String^>(values->Lookup(fromKey))->Data();
*toCurrency = static_cast<String^>(values->Lookup(toKey))->Data();
*fromCurrency = static_cast<String ^>(values->Lookup(fromKey))->Data();
*toCurrency = static_cast<String ^>(values->Lookup(toKey))->Data();
return true;
}
@@ -803,12 +807,12 @@ bool CurrencyDataLoader::TryGetLastUsedCurrenciesFromLocalSettings(_Out_ wstring
void CurrencyDataLoader::SaveSelectedUnitsToLocalSettings(_In_ const SelectedUnits& selectedUnits)
{
String^ fromKey = UnitConverterResourceKeys::CurrencyUnitFromKey;
String^ toKey = UnitConverterResourceKeys::CurrencyUnitToKey;
ApplicationDataContainer^ localSettings = ApplicationData::Current->LocalSettings;
String ^ fromKey = UnitConverterResourceKeys::CurrencyUnitFromKey;
String ^ toKey = UnitConverterResourceKeys::CurrencyUnitToKey;
ApplicationDataContainer ^ localSettings = ApplicationData::Current->LocalSettings;
if (localSettings != nullptr && localSettings->Values != nullptr)
{
IPropertySet^ values = localSettings->Values;
IPropertySet ^ values = localSettings->Values;
values->Insert(fromKey, StringReference(selectedUnits.first.c_str()));
values->Insert(toKey, StringReference(selectedUnits.second.c_str()));
}

View File

@@ -11,7 +11,8 @@ namespace CalculatorApp
{
namespace ViewModel
{
public enum class CurrencyLoadStatus
public
enum class CurrencyLoadStatus
{
NotLoaded = 0,
FailedToLoad = 1,
@@ -42,16 +43,18 @@ namespace CalculatorApp
struct CurrencyUnitMetadata
{
CurrencyUnitMetadata(const std::wstring& s) : symbol(s) {}
CurrencyUnitMetadata(const std::wstring& s)
: symbol(s)
{
}
const std::wstring symbol;
};
class CurrencyDataLoader : public UCM::IConverterDataLoader,
public UCM::ICurrencyConverterDataLoader
class CurrencyDataLoader : public UCM::IConverterDataLoader, public UCM::ICurrencyConverterDataLoader
{
public:
CurrencyDataLoader(_In_ std::unique_ptr<CalculatorApp::DataLoaders::ICurrencyHttpClient> client);
CurrencyDataLoader(_In_ std::unique_ptr<CalculatorApp::DataLoaders::ICurrencyHttpClient> client, const wchar_t* overrideLanguage = nullptr);
~CurrencyDataLoader();
bool LoadFinished();
@@ -69,12 +72,13 @@ namespace CalculatorApp
// ICurrencyConverterDataLoader
void SetViewModelCallback(const std::shared_ptr<UCM::IViewModelCurrencyCallback>& callback) override;
std::pair<std::wstring, std::wstring> GetCurrencySymbols(const UCM::Unit& unit1, const UCM::Unit& unit2) override;
std::pair<std::wstring, std::wstring> GetCurrencyRatioEquality(_In_ const UnitConversionManager::Unit& unit1, _In_ const UnitConversionManager::Unit& unit2) override;
std::pair<std::wstring, std::wstring>
GetCurrencyRatioEquality(_In_ const UnitConversionManager::Unit& unit1, _In_ const UnitConversionManager::Unit& unit2) override;
std::wstring GetCurrencyTimestamp() override;
concurrency::task<bool> TryLoadDataFromCacheAsync() override;
concurrency::task<bool> TryLoadDataFromWebAsync() override;
concurrency::task<bool> TryLoadDataFromWebOverrideAsync() override;
std::future<bool> TryLoadDataFromCacheAsync() override;
std::future<bool> TryLoadDataFromWebAsync() override;
std::future<bool> TryLoadDataFromWebOverrideAsync() override;
// ICurrencyConverterDataLoader
void OnNetworkBehaviorChanged(CalculatorApp::NetworkAccessBehavior newBehavior);
@@ -83,15 +87,15 @@ namespace CalculatorApp
void ResetLoadStatus();
void NotifyDataLoadFinished(bool didLoad);
concurrency::task<bool> TryFinishLoadFromCacheAsync();
std::future<bool> TryFinishLoadFromCacheAsync();
bool TryParseWebResponses(
_In_ Platform::String^ staticDataJson,
_In_ Platform::String^ allRatiosJson,
_In_ Platform::String ^ staticDataJson,
_In_ Platform::String ^ allRatiosJson,
_Inout_ std::vector<UCM::CurrencyStaticData>& staticData,
_Inout_ CurrencyRatioMap& allRatiosData);
bool TryParseStaticData(_In_ Platform::String^ rawJson, _Inout_ std::vector<UCM::CurrencyStaticData>& staticData);
bool TryParseAllRatiosData(_In_ Platform::String^ rawJson, _Inout_ CurrencyRatioMap& allRatiosData);
bool TryParseStaticData(_In_ Platform::String ^ rawJson, _Inout_ std::vector<UCM::CurrencyStaticData>& staticData);
bool TryParseAllRatiosData(_In_ Platform::String ^ rawJson, _Inout_ CurrencyRatioMap& allRatiosData);
concurrency::task<void> FinalizeUnits(_In_ const std::vector<UCM::CurrencyStaticData>& staticData, _In_ const CurrencyRatioMap& ratioMap);
void GuaranteeSelectedUnits();
@@ -106,7 +110,7 @@ namespace CalculatorApp
void SaveSelectedUnitsToLocalSettings(_In_ const SelectedUnits& selectedUnits);
private:
Platform::String^ m_responseLanguage;
Platform::String ^ m_responseLanguage;
std::unique_ptr<CalculatorApp::DataLoaders::ICurrencyHttpClient> m_client;
bool m_isRtlLanguage;
@@ -118,14 +122,14 @@ namespace CalculatorApp
std::shared_ptr<UCM::IViewModelCurrencyCallback> m_vmCallback;
Windows::Globalization::NumberFormatting::DecimalFormatter^ m_ratioFormatter;
Windows::Globalization::NumberFormatting::DecimalFormatter ^ m_ratioFormatter;
std::wstring m_ratioFormat;
Windows::Foundation::DateTime m_cacheTimestamp;
std::wstring m_timestampFormat;
CurrencyLoadStatus m_loadStatus;
CalculatorApp::NetworkManager^ m_networkManager;
CalculatorApp::NetworkManager ^ m_networkManager;
CalculatorApp::NetworkAccessBehavior m_networkAccessBehavior;
Windows::Foundation::EventRegistrationToken m_networkBehaviorToken;
bool m_meteredOverrideSet;

View File

@@ -1,35 +1,38 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pch.h"
#include "CurrencyHttpClient.h"
#ifdef USE_MOCK_DATA
#include "DataLoaderMockConstants.h"
#else
#include "DataLoaderConstants.h"
#endif
using namespace CalculatorApp::DataLoaders;
using namespace Platform;
using namespace std;
using namespace Windows::Foundation;
using namespace Windows::Web::Http;
static constexpr auto sc_MetadataUriLocalizeFor = L"https://go.microsoft.com/fwlink/?linkid=2041093&localizeFor=";
static constexpr auto sc_RatiosUriRelativeTo = L"https://go.microsoft.com/fwlink/?linkid=2041339&localCurrency=";
CurrencyHttpClient::CurrencyHttpClient() :
m_client(ref new HttpClient()),
m_responseLanguage(L"en-US")
CurrencyHttpClient::CurrencyHttpClient()
: m_client(ref new HttpClient())
, m_responseLanguage(L"en-US")
{
}
void CurrencyHttpClient::SetSourceCurrencyCode(String^ sourceCurrencyCode)
void CurrencyHttpClient::SetSourceCurrencyCode(String ^ sourceCurrencyCode)
{
m_sourceCurrencyCode = sourceCurrencyCode;
}
void CurrencyHttpClient::SetResponseLanguage(String^ responseLanguage)
void CurrencyHttpClient::SetResponseLanguage(String ^ responseLanguage)
{
m_responseLanguage = responseLanguage;
}
IAsyncOperationWithProgress<String^, HttpProgress>^ CurrencyHttpClient::GetCurrencyMetadata()
IAsyncOperationWithProgress<String ^, HttpProgress> ^ CurrencyHttpClient::GetCurrencyMetadata()
{
wstring uri = wstring{ sc_MetadataUriLocalizeFor } + m_responseLanguage->Data();
auto metadataUri = ref new Uri(StringReference(uri.c_str()));
@@ -37,7 +40,7 @@ IAsyncOperationWithProgress<String^, HttpProgress>^ CurrencyHttpClient::GetCurre
return m_client->GetStringAsync(metadataUri);
}
IAsyncOperationWithProgress<String^, HttpProgress>^ CurrencyHttpClient::GetCurrencyRatios()
IAsyncOperationWithProgress<String ^, HttpProgress> ^ CurrencyHttpClient::GetCurrencyRatios()
{
wstring uri = wstring{ sc_RatiosUriRelativeTo } + m_sourceCurrencyCode->Data();
auto ratiosUri = ref new Uri(StringReference(uri.c_str()));

View File

@@ -14,16 +14,16 @@ namespace CalculatorApp
public:
CurrencyHttpClient();
void SetSourceCurrencyCode(Platform::String^ sourceCurrencyCode) override;
void SetResponseLanguage(Platform::String^ responseLanguage) override;
void SetSourceCurrencyCode(Platform::String ^ sourceCurrencyCode) override;
void SetResponseLanguage(Platform::String ^ responseLanguage) override;
Windows::Foundation::IAsyncOperationWithProgress<Platform::String^, Windows::Web::Http::HttpProgress>^ GetCurrencyMetadata() override;
Windows::Foundation::IAsyncOperationWithProgress<Platform::String^, Windows::Web::Http::HttpProgress>^ GetCurrencyRatios() override;
Windows::Foundation::IAsyncOperationWithProgress<Platform::String ^, Windows::Web::Http::HttpProgress> ^ GetCurrencyMetadata() override;
Windows::Foundation::IAsyncOperationWithProgress<Platform::String ^, Windows::Web::Http::HttpProgress> ^ GetCurrencyRatios() override;
private:
Windows::Web::Http::HttpClient^ m_client;
Platform::String^ m_responseLanguage;
Platform::String^ m_sourceCurrencyCode;
Windows::Web::Http::HttpClient ^ m_client;
Platform::String ^ m_responseLanguage;
Platform::String ^ m_sourceCurrencyCode;
};
}
}

View File

@@ -0,0 +1,13 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
namespace CalculatorApp
{
namespace DataLoaders
{
static constexpr auto sc_MetadataUriLocalizeFor = L"https://go.microsoft.com/fwlink/?linkid=2091028&localizeFor=";
static constexpr auto sc_RatiosUriRelativeTo = L"https://go.microsoft.com/fwlink/?linkid=2091307&localCurrency=";
}
}

View File

@@ -10,13 +10,15 @@ namespace CalculatorApp
class ICurrencyHttpClient
{
public:
virtual ~ICurrencyHttpClient() {}
virtual ~ICurrencyHttpClient()
{
}
virtual void SetSourceCurrencyCode(Platform::String^ sourceCurrencyCode) = 0;
virtual void SetResponseLanguage(Platform::String^ responseLanguage) = 0;
virtual void SetSourceCurrencyCode(Platform::String ^ sourceCurrencyCode) = 0;
virtual void SetResponseLanguage(Platform::String ^ responseLanguage) = 0;
virtual Windows::Foundation::IAsyncOperationWithProgress<Platform::String^, Windows::Web::Http::HttpProgress>^ GetCurrencyMetadata() = 0;
virtual Windows::Foundation::IAsyncOperationWithProgress<Platform::String^, Windows::Web::Http::HttpProgress>^ GetCurrencyRatios() = 0;
virtual Windows::Foundation::IAsyncOperationWithProgress<Platform::String ^, Windows::Web::Http::HttpProgress> ^ GetCurrencyMetadata() = 0;
virtual Windows::Foundation::IAsyncOperationWithProgress<Platform::String ^, Windows::Web::Http::HttpProgress> ^ GetCurrencyRatios() = 0;
};
}
}

View File

@@ -1,11 +1,12 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace CalculatorApp
{
namespace ViewModel
{
private enum UnitConverterUnits
private
enum UnitConverterUnits
{
UnitStart = 0,
Area_Acre = UnitStart + 1,
@@ -162,7 +163,8 @@ namespace CalculatorApp
Data_Zebibytes = UnitStart + 162,
Data_Zetabits = UnitStart + 163,
Data_Zetabytes = UnitStart + 164,
UnitEnd = Data_Zetabytes
Area_Pyeong = UnitStart + 165,
UnitEnd = Area_Pyeong
};
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -12,10 +12,20 @@ namespace CalculatorApp
{
struct OrderedUnit : UnitConversionManager::Unit
{
OrderedUnit(){}
OrderedUnit()
{
}
OrderedUnit(int id, std::wstring name, std::wstring abbreviation, int order, bool isConversionSource = false, bool isConversionTarget = false, bool isWhimsical = false)
: UnitConversionManager::Unit(id, name, abbreviation, isConversionSource, isConversionTarget, isWhimsical), order(order)
OrderedUnit(
int id,
std::wstring name,
std::wstring abbreviation,
int order,
bool isConversionSource = false,
bool isConversionTarget = false,
bool isWhimsical = false)
: UnitConversionManager::Unit(id, name, abbreviation, isConversionSource, isConversionTarget, isWhimsical)
, order(order)
{
}
@@ -31,11 +41,21 @@ namespace CalculatorApp
struct ExplicitUnitConversionData : UnitConversionManager::ConversionData
{
ExplicitUnitConversionData(){}
ExplicitUnitConversionData(CalculatorApp::Common::ViewMode categoryId, int parentUnitId, int unitId, double ratio, double offset, bool offsetFirst = false) :
categoryId(categoryId), parentUnitId(parentUnitId), unitId(unitId), UnitConversionManager::ConversionData(ratio, offset, offsetFirst)
ExplicitUnitConversionData()
{
}
ExplicitUnitConversionData(
CalculatorApp::Common::ViewMode categoryId,
int parentUnitId,
int unitId,
double ratio,
double offset,
bool offsetFirst = false)
: categoryId(categoryId)
, parentUnitId(parentUnitId)
, unitId(unitId)
, UnitConversionManager::ConversionData(ratio, offset, offsetFirst)
{
}
CalculatorApp::Common::ViewMode categoryId;
@@ -43,32 +63,33 @@ namespace CalculatorApp
int unitId;
};
class UnitConverterDataLoader : public UnitConversionManager::IConverterDataLoader,
public std::enable_shared_from_this<UnitConverterDataLoader>
class UnitConverterDataLoader : public UnitConversionManager::IConverterDataLoader, public std::enable_shared_from_this<UnitConverterDataLoader>
{
public:
UnitConverterDataLoader(Windows::Globalization::GeographicRegion^ region);
UnitConverterDataLoader(Windows::Globalization::GeographicRegion ^ region);
private:
// IConverterDataLoader
void LoadData() override;
std::vector<UnitConversionManager::Category> LoadOrderedCategories() override;
std::vector<UnitConversionManager::Unit> LoadOrderedUnits(const UnitConversionManager::Category& c) override;
std::unordered_map<UnitConversionManager::Unit, UnitConversionManager::ConversionData, UnitConversionManager::UnitHash> LoadOrderedRatios(const UnitConversionManager::Unit& unit) override;
std::unordered_map<UnitConversionManager::Unit, UnitConversionManager::ConversionData, UnitConversionManager::UnitHash>
LoadOrderedRatios(const UnitConversionManager::Unit& unit) override;
bool SupportsCategory(const UnitConversionManager::Category& target) override;
// IConverterDataLoader
void GetCategories(_In_ std::shared_ptr<std::vector<UnitConversionManager::Category>> categoriesList);
void GetUnits(_In_ std::unordered_map<CalculatorApp::Common::ViewMode, std::vector<CalculatorApp::ViewModel::OrderedUnit>>& unitMap);
void GetConversionData(_In_ std::unordered_map<CalculatorApp::Common::ViewMode, std::unordered_map<int, double>>& categoryToUnitConversionMap);
void GetExplicitConversionData(_In_ std::unordered_map<int, std::unordered_map<int, UnitConversionManager::ConversionData>>& unitToUnitConversionList);
void
GetExplicitConversionData(_In_ std::unordered_map<int, std::unordered_map<int, UnitConversionManager::ConversionData>>& unitToUnitConversionList);
std::wstring GetLocalizedStringName(_In_ Platform::String^ stringId);
std::wstring GetLocalizedStringName(_In_ Platform::String ^ stringId);
std::shared_ptr<std::vector<UnitConversionManager::Category>> m_categoryList;
std::shared_ptr<UnitConversionManager::CategoryToUnitVectorMap> m_categoryToUnits;
std::shared_ptr<UnitConversionManager::UnitToUnitToConversionDataMap> m_ratioMap;
Platform::String^ m_currentRegionCode;
Platform::String ^ m_currentRegionCode;
};
}
}