forked from microsoft/calculator
-
Notifications
You must be signed in to change notification settings - Fork 1
/
UnitConverterViewModel.h
459 lines (396 loc) · 19.6 KB
/
UnitConverterViewModel.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
#include "CalcManager/UnitConverter.h"
#include "Common/Utils.h"
#include "Common/NetworkManager.h"
#include "Common/Automation/NarratorAnnouncement.h"
#include "Common/CalculatorButtonUser.h"
#include "Common/NavCategory.h"
namespace CalculatorApp
{
namespace ViewModel
{
[Windows::UI::Xaml::Data::Bindable] public ref class Category sealed : public Windows::UI::Xaml::Data::INotifyPropertyChanged
{
internal : Category(const UnitConversionManager::Category& category)
: m_original(category)
{
}
public:
OBSERVABLE_OBJECT();
property Platform::String
^ Name { Platform::String ^ get() { return ref new Platform::String(m_original.name.c_str()); } }
property Windows::UI::Xaml::Visibility NegateVisibility
{
Windows::UI::Xaml::Visibility get()
{
return m_original.supportsNegative ? Windows::UI::Xaml::Visibility::Visible : Windows::UI::Xaml::Visibility::Collapsed;
}
}
internal : const UnitConversionManager::Category& GetModelCategory() const
{
return m_original;
}
private:
const UnitConversionManager::Category m_original;
};
[Windows::UI::Xaml::Data::Bindable] public ref class Unit sealed : public Windows::UI::Xaml::Data::INotifyPropertyChanged
{
internal : Unit(const UnitConversionManager::Unit& unit)
: m_original(unit)
{
}
public:
OBSERVABLE_OBJECT();
property Platform::String
^ Name { Platform::String ^ get() { return ref new Platform::String(m_original.name.c_str()); } }
property Platform::String
^ AccessibleName { Platform::String ^ get() { return ref new Platform::String(m_original.accessibleName.c_str()); } }
property Platform::String
^ Abbreviation { Platform::String ^ get() { return ref new Platform::String(m_original.abbreviation.c_str()); } }
// This method is used to return the desired automation name for default unit in UnitConverter combo box.
Platform::String
^ ToString() override
{
return AccessibleName;
}
internal : const UnitConversionManager::Unit& GetModelUnit() const
{
return m_original;
}
private:
const UnitConversionManager::Unit m_original;
};
[Windows::UI::Xaml::Data::Bindable] public ref class SupplementaryResult sealed : public Windows::UI::Xaml::Data::INotifyPropertyChanged
{
internal : SupplementaryResult(Platform::String ^ value, Unit ^ unit)
: m_Value(value)
, m_Unit(unit)
{
}
bool IsWhimsical() const
{
return m_Unit->GetModelUnit().isWhimsical;
}
Platform::String ^ GetLocalizedAutomationName();
public:
OBSERVABLE_OBJECT();
OBSERVABLE_PROPERTY_R(Platform::String ^, Value);
OBSERVABLE_PROPERTY_R(CalculatorApp::ViewModel::Unit ^, Unit);
};
interface class IActivatable
{
virtual property bool IsActive;
};
template <typename TActivatable>
ref class Activatable sealed : public IActivatable
{
private:
TActivatable m_activatable;
public:
Activatable(TActivatable activatable)
: m_activatable(activatable)
{
}
virtual property bool IsActive
{
bool get()
{
return m_activatable->IsActive;
}
void set(bool value)
{
m_activatable->IsActive = value;
}
}
};
template <typename TActivatable>
IActivatable
^ AsActivatable(TActivatable activatable) { return ref new Activatable<TActivatable>(activatable); }
[Windows::UI::Xaml::Data::Bindable] public ref class UnitConverterViewModel sealed : public Windows::UI::Xaml::Data::INotifyPropertyChanged
{
internal : UnitConverterViewModel(const std::shared_ptr<UnitConversionManager::IUnitConverter>& model);
public:
OBSERVABLE_OBJECT_CALLBACK(OnPropertyChanged);
OBSERVABLE_PROPERTY_R(Windows::Foundation::Collections::IObservableVector<Category ^> ^, Categories);
OBSERVABLE_PROPERTY_RW(CalculatorApp::Common::ViewMode, Mode);
OBSERVABLE_PROPERTY_R(Windows::Foundation::Collections::IObservableVector<Unit ^> ^, Units);
OBSERVABLE_PROPERTY_RW(Platform::String ^, CurrencySymbol1);
OBSERVABLE_PROPERTY_RW(Unit ^, Unit1);
OBSERVABLE_PROPERTY_RW(Platform::String ^, Value1);
OBSERVABLE_PROPERTY_RW(Platform::String ^, CurrencySymbol2);
OBSERVABLE_PROPERTY_RW(Unit ^, Unit2);
OBSERVABLE_PROPERTY_RW(Platform::String ^, Value2);
OBSERVABLE_NAMED_PROPERTY_R(Windows::Foundation::Collections::IObservableVector<SupplementaryResult ^> ^, SupplementaryResults);
OBSERVABLE_PROPERTY_RW(bool, Value1Active);
OBSERVABLE_PROPERTY_RW(bool, Value2Active);
OBSERVABLE_PROPERTY_RW(Platform::String ^, Value1AutomationName);
OBSERVABLE_PROPERTY_RW(Platform::String ^, Value2AutomationName);
OBSERVABLE_PROPERTY_RW(Platform::String ^, Unit1AutomationName);
OBSERVABLE_PROPERTY_RW(Platform::String ^, Unit2AutomationName);
OBSERVABLE_PROPERTY_RW(CalculatorApp::Common::Automation::NarratorAnnouncement ^, Announcement);
OBSERVABLE_PROPERTY_RW(bool, IsDecimalEnabled);
OBSERVABLE_PROPERTY_RW(bool, IsDropDownOpen);
OBSERVABLE_PROPERTY_RW(bool, IsDropDownEnabled);
OBSERVABLE_NAMED_PROPERTY_RW(bool, IsCurrencyLoadingVisible);
OBSERVABLE_NAMED_PROPERTY_R(bool, IsCurrencyCurrentCategory);
OBSERVABLE_PROPERTY_RW(Platform::String ^, CurrencyRatioEquality);
OBSERVABLE_PROPERTY_RW(Platform::String ^, CurrencyRatioEqualityAutomationName);
OBSERVABLE_PROPERTY_RW(Platform::String ^, CurrencyTimestamp);
OBSERVABLE_NAMED_PROPERTY_RW(CalculatorApp::NetworkAccessBehavior, NetworkBehavior);
OBSERVABLE_NAMED_PROPERTY_RW(bool, CurrencyDataLoadFailed);
OBSERVABLE_NAMED_PROPERTY_RW(bool, CurrencyDataIsWeekOld);
public:
property Category ^ CurrentCategory
{
Category ^ get() { return m_CurrentCategory; }
void set(Category ^ value)
{
if (m_CurrentCategory == value)
{
return;
}
m_CurrentCategory = value;
if (value != nullptr)
{
auto currentCategory = value->GetModelCategory();
IsCurrencyCurrentCategory = currentCategory.id == CalculatorApp::Common::NavCategory::Serialize(CalculatorApp::Common::ViewMode::Currency);
}
RaisePropertyChanged("CurrentCategory");
}
}
property Windows::UI::Xaml::Visibility SupplementaryVisibility
{
Windows::UI::Xaml::Visibility get()
{
return SupplementaryResults->Size > 0 ? Windows::UI::Xaml::Visibility::Visible : Windows::UI::Xaml::Visibility::Collapsed;
}
}
property Windows::UI::Xaml::Visibility CurrencySymbolVisibility
{
Windows::UI::Xaml::Visibility get()
{
return (CurrencySymbol1->IsEmpty() || CurrencySymbol2->IsEmpty()) ? Windows::UI::Xaml::Visibility::Collapsed
: Windows::UI::Xaml::Visibility::Visible;
}
}
COMMAND_FOR_METHOD(CategoryChanged, UnitConverterViewModel::OnCategoryChanged);
COMMAND_FOR_METHOD(UnitChanged, UnitConverterViewModel::OnUnitChanged);
COMMAND_FOR_METHOD(SwitchActive, UnitConverterViewModel::OnSwitchActive);
COMMAND_FOR_METHOD(ButtonPressed, UnitConverterViewModel::OnButtonPressed);
COMMAND_FOR_METHOD(CopyCommand, UnitConverterViewModel::OnCopyCommand);
COMMAND_FOR_METHOD(PasteCommand, UnitConverterViewModel::OnPasteCommand);
void AnnounceConversionResult();
internal : void ResetView();
void PopulateData();
NumbersAndOperatorsEnum MapCharacterToButtonId(const wchar_t ch, bool& canSendNegate);
void DisplayPasteError();
void OnValueActivated(IActivatable ^ control);
void OnPaste(Platform::String ^ stringToPaste);
void OnCopyCommand(Platform::Object ^ parameter);
void OnPasteCommand(Platform::Object ^ parameter);
enum class CurrencyFormatterParameter
{
Default,
ForValue1,
ForValue2,
};
Platform::String
^ GetLocalizedAutomationName(
_In_ Platform::String ^ displayvalue,
_In_ Platform::String ^ unitname,
_In_ Platform::String ^ format,
_In_ CurrencyFormatterParameter cfp);
Platform::String
^ GetLocalizedConversionResultStringFormat(
_In_ Platform::String ^ fromValue,
_In_ Platform::String ^ fromUnit,
_In_ Platform::String ^ toValue,
_In_ Platform::String ^ toUnit);
void UpdateValue1AutomationName();
void UpdateValue2AutomationName();
// Saving And Restoring User Preferences of Category and Associated-Units across Sessions.
void SaveUserPreferences();
void RestoreUserPreferences();
void OnCurrencyDataLoadFinished(bool didLoad);
void OnCurrencyTimestampUpdated(_In_ const std::wstring& timestamp, bool isWeekOld);
void RefreshCurrencyRatios();
void OnNetworkBehaviorChanged(_In_ CalculatorApp::NetworkAccessBehavior newBehavior);
const std::wstring& GetValueFromUnlocalized() const
{
return m_valueFromUnlocalized;
}
const std::wstring& GetValueToUnlocalized() const
{
return m_valueToUnlocalized;
}
// used by UnitConverterVMCallback
void UpdateDisplay(const std::wstring& from, const std::wstring& to);
void UpdateSupplementaryResults(const std::vector<std::tuple<std::wstring, UnitConversionManager::Unit>>& suggestedValues);
void OnMaxDigitsReached();
void BuildUnitList(const std::vector<UnitConversionManager::Unit>& modelUnitList);
Unit ^ FindUnitInList(UnitConversionManager::Unit target);
void SetSelectedUnits();
private:
void InitializeView();
void OnPropertyChanged(Platform::String ^ prop);
void OnCategoryChanged(Platform::Object ^ unused);
void OnUnitChanged(Platform::Object ^ unused);
void OnSwitchActive(Platform::Object ^ unused);
UnitConversionManager::Command CommandFromButtonId(CalculatorApp::NumbersAndOperatorsEnum button);
void SupplementaryResultsTimerTick(Windows::System::Threading::ThreadPoolTimer ^ timer);
void SupplementaryResultsTimerCancel(Windows::System::Threading::ThreadPoolTimer ^ timer);
void RefreshSupplementaryResults();
void UpdateInputBlocked(_In_ const std::wstring& currencyInput);
void UpdateCurrencyFormatter();
void UpdateIsDecimalEnabled();
bool UnitsAreValid();
void ResetCategory();
void OnButtonPressed(Platform::Object ^ parameter);
Platform::String ^ ConvertToLocalizedString(const std::wstring& stringToLocalize, bool allowPartialStrings, CurrencyFormatterParameter cfp);
std::shared_ptr<UnitConversionManager::IUnitConverter> m_model;
wchar_t m_decimalSeparator;
enum class ConversionParameter
{
Source,
Target
} m_value1cp;
property CurrencyFormatterParameter CurrencyFormatterParameterFrom
{
CurrencyFormatterParameter get()
{
return m_value1cp == ConversionParameter::Source ? CurrencyFormatterParameter::ForValue1 : CurrencyFormatterParameter::ForValue2;
}
}
property CurrencyFormatterParameter CurrencyFormatterParameterTo
{
CurrencyFormatterParameter get()
{
return m_value1cp == ConversionParameter::Target ? CurrencyFormatterParameter::ForValue1 : CurrencyFormatterParameter::ForValue2;
}
}
property Windows::Globalization::NumberFormatting::CurrencyFormatter^ CurrencyFormatterFrom
{
Windows::Globalization::NumberFormatting::CurrencyFormatter^ get()
{
return m_value1cp == ConversionParameter::Source ? m_currencyFormatter1 : m_currencyFormatter2;
}
}
property Windows::Globalization::NumberFormatting::CurrencyFormatter^ CurrencyFormatterTo
{
Windows::Globalization::NumberFormatting::CurrencyFormatter^ get()
{
return m_value1cp == ConversionParameter::Target ? m_currencyFormatter1 : m_currencyFormatter2;
}
}
property Platform::String^ ValueFrom
{
Platform::String^ get() { return m_value1cp == ConversionParameter::Source ? Value1 : Value2; }
void set(Platform::String^ value) { m_value1cp == ConversionParameter::Source ? Value1 = value : Value2 = value; }
}
property Unit^ UnitFrom
{
Unit^ get() { return m_value1cp == ConversionParameter::Source ? Unit1 : Unit2; }
void set(Unit^ value) { m_value1cp == ConversionParameter::Source ? Unit1 = value : Unit2 = value; }
}
property Platform::String^ ValueTo
{
Platform::String^ get() { return m_value1cp == ConversionParameter::Target ? Value1 : Value2; }
void set(Platform::String^ value) { m_value1cp == ConversionParameter::Target ? Value1 = value : Value2 = value; }
}
property Unit^ UnitTo
{
Unit^ get() { return m_value1cp == ConversionParameter::Target ? Unit1 : Unit2; }
void set(Unit^ value) { m_value1cp == ConversionParameter::Target ? Unit1 = value : Unit2 = value; }
}
void SwitchConversionParameters()
{
m_value1cp = m_value1cp == ConversionParameter::Source ? ConversionParameter::Target : ConversionParameter::Source;
}
private:
bool m_isInputBlocked;
Windows::System::Threading::ThreadPoolTimer ^ m_supplementaryResultsTimer;
bool m_resettingTimer;
std::vector<std::tuple<std::wstring, UnitConversionManager::Unit>> m_cachedSuggestedValues;
std::mutex m_cacheMutex;
Windows::Globalization::NumberFormatting::DecimalFormatter ^ m_decimalFormatter;
Windows::Globalization::NumberFormatting::CurrencyFormatter ^ m_currencyFormatter;
Windows::Globalization::NumberFormatting::CurrencyFormatter ^ m_currencyFormatter1;
Windows::Globalization::NumberFormatting::CurrencyFormatter ^ m_currencyFormatter2;
std::wstring m_valueFromUnlocalized;
std::wstring m_valueToUnlocalized;
bool m_relocalizeStringOnSwitch;
Platform::String ^ m_localizedValueFromFormat;
Platform::String ^ m_localizedValueFromDecimalFormat;
Platform::String ^ m_localizedValueToFormat;
Platform::String ^ m_localizedConversionResultFormat;
Platform::String ^ m_localizedInputUnitName;
Platform::String ^ m_localizedOutputUnitName;
bool m_isValue1Updating;
bool m_isValue2Updating;
std::wstring m_lastAnnouncedFrom;
std::wstring m_lastAnnouncedTo;
Platform::String ^ m_lastAnnouncedConversionResult;
Category ^ m_CurrentCategory;
bool m_isCurrencyDataLoaded;
};
class UnitConverterVMCallback : public UnitConversionManager::IUnitConverterVMCallback
{
public:
UnitConverterVMCallback(UnitConverterViewModel ^ viewModel)
: m_viewModel(viewModel)
{
}
void DisplayCallback(const std::wstring& from, const std::wstring& to) override
{
m_viewModel->UpdateDisplay(from, to);
}
void SuggestedValueCallback(const std::vector<std::tuple<std::wstring, UnitConversionManager::Unit>>& suggestedValues) override
{
m_viewModel->UpdateSupplementaryResults(suggestedValues);
}
void MaxDigitsReached()
{
m_viewModel->OnMaxDigitsReached();
}
private:
UnitConverterViewModel ^ m_viewModel;
};
class ViewModelCurrencyCallback : public UnitConversionManager::IViewModelCurrencyCallback
{
public:
ViewModelCurrencyCallback(UnitConverterViewModel ^ viewModel)
: m_viewModel(viewModel)
{
}
void CurrencyDataLoadFinished(bool didLoad) override
{
m_viewModel->OnCurrencyDataLoadFinished(didLoad);
}
void CurrencySymbolsCallback(const std::wstring& symbol1, const std::wstring& symbol2) override
{
Platform::String ^ sym1 = Platform::StringReference(symbol1.c_str());
Platform::String ^ sym2 = Platform::StringReference(symbol2.c_str());
bool value1Active = m_viewModel->Value1Active;
m_viewModel->CurrencySymbol1 = value1Active ? sym1 : sym2;
m_viewModel->CurrencySymbol2 = value1Active ? sym2 : sym1;
}
void CurrencyRatiosCallback(_In_ const std::wstring& ratioEquality, _In_ const std::wstring& accRatioEquality) override
{
m_viewModel->CurrencyRatioEquality = ref new Platform::String(ratioEquality.c_str());
m_viewModel->CurrencyRatioEqualityAutomationName = ref new Platform::String(accRatioEquality.c_str());
}
void CurrencyTimestampCallback(_In_ const std::wstring& timestamp, bool isWeekOld) override
{
m_viewModel->OnCurrencyTimestampUpdated(timestamp, isWeekOld);
}
void NetworkBehaviorChanged(_In_ int newBehavior) override
{
m_viewModel->OnNetworkBehaviorChanged(static_cast<CalculatorApp::NetworkAccessBehavior>(newBehavior));
}
private:
UnitConverterViewModel ^ m_viewModel;
};
}
}