mirror of
https://github.com/Microsoft/calculator.git
synced 2025-08-23 06:25:19 -07:00
Enable converters
This commit is contained in:
parent
f93281dc78
commit
93fdfe02c6
38 changed files with 7255 additions and 957 deletions
|
@ -20,6 +20,7 @@
|
|||
<AndroidManifest>Properties\AndroidManifest.xml</AndroidManifest>
|
||||
<AndroidUseIntermediateDesignerFile>True</AndroidUseIntermediateDesignerFile>
|
||||
<ResourcesDirectory>..\Calculator.Shared\Strings</ResourcesDirectory>
|
||||
<LangVersion>7.3</LangVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
|
|
|
@ -5,7 +5,7 @@ using System.Text;
|
|||
|
||||
namespace CalculatorApp
|
||||
{
|
||||
public class CalculatorList<TType> : IEnumerable<TType>, IEnumerable
|
||||
public class CalculatorList<TType> : IEnumerable<TType>, IEnumerable
|
||||
{
|
||||
List<TType> m_vector;
|
||||
|
||||
|
@ -19,7 +19,22 @@ namespace CalculatorApp
|
|||
m_vector = new List<TType>(source.m_vector);
|
||||
}
|
||||
|
||||
public bool GetAt(int index, out TType item)
|
||||
public TType this[int index]
|
||||
{
|
||||
get => m_vector[index];
|
||||
}
|
||||
|
||||
public TType this[uint index]
|
||||
{
|
||||
get => m_vector[(int)index];
|
||||
}
|
||||
|
||||
public TType At(int index)
|
||||
{
|
||||
return m_vector[index];
|
||||
}
|
||||
|
||||
public bool GetAt(int index, out TType item)
|
||||
{
|
||||
item = m_vector[index];
|
||||
return true;
|
||||
|
@ -70,12 +85,27 @@ namespace CalculatorApp
|
|||
return true;
|
||||
}
|
||||
|
||||
public bool Append(TType item)
|
||||
public void Add(TType item)
|
||||
{
|
||||
m_vector.Add(item);
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool Append(TType item)
|
||||
{
|
||||
m_vector.Add(item);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void EmplaceBack(TType item)
|
||||
{
|
||||
m_vector.Add(item);
|
||||
}
|
||||
|
||||
public void PushBack(TType item)
|
||||
{
|
||||
m_vector.Add(item);
|
||||
}
|
||||
|
||||
public bool RemoveAtEnd()
|
||||
{
|
||||
m_vector.RemoveAt(m_vector.Count - 1);
|
||||
|
@ -88,6 +118,28 @@ namespace CalculatorApp
|
|||
return true;
|
||||
}
|
||||
|
||||
public bool IsEmpty()
|
||||
{
|
||||
return m_vector.Count == 0;
|
||||
}
|
||||
|
||||
public uint Size()
|
||||
{
|
||||
return (uint)m_vector.Count;
|
||||
}
|
||||
|
||||
public void Sort(Func<TType, TType, bool> comparison)
|
||||
{
|
||||
m_vector.Sort((t1, t2) => comparison(t1, t2) ? -1 : 1);
|
||||
}
|
||||
|
||||
public int IndexOf(TType item)
|
||||
{
|
||||
return m_vector.IndexOf(item);
|
||||
}
|
||||
|
||||
public int Count => m_vector.Count;
|
||||
|
||||
public bool GetString(out string expression)
|
||||
{
|
||||
// UNO TODO
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
|
||||
namespace CalculatorApp
|
||||
{
|
||||
public class CalculatorObservableCollection<TType> : ObservableCollection<TType>
|
||||
{
|
||||
public void Append(TType item)
|
||||
{
|
||||
Add(item);
|
||||
}
|
||||
|
||||
public TType GetAt(int index)
|
||||
{
|
||||
return this[index];
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -22,6 +22,7 @@
|
|||
<Compile Include="$(MSBuildThisFileDirectory)CalcManager\CalculatorManager.Interop.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)CalcManager\CalculatorManager.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)CalcManager\CalculatorMode.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)CalcManager\CalculatorObservableCollection.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)CalcManager\CCalcEngine.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)CalcManager\CCommand.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)CalcManager\Command.cs" />
|
||||
|
@ -34,10 +35,12 @@
|
|||
<Compile Include="$(MSBuildThisFileDirectory)Common\AppLifecycleLogger.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Common\AppResourceProvider.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Common\Automation\NarratorAnnouncement.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Common\Automation\NarratorNotifier.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Common\BindableBase.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Common\CalculatorButtonPressedEventArgs.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Common\CalculatorButtonUser.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Common\CalculatorDisplay.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Common\ConversionResultTaskHelper.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Common\CopyPasteManager.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Common\DateCalculator.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Common\DelegateCommand.cs" />
|
||||
|
@ -48,13 +51,16 @@
|
|||
<Compile Include="$(MSBuildThisFileDirectory)Common\LocalizationStringUtil.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Common\MyVirtualKey.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Common\NavCategory.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Common\NetworkManager.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Common\TitleBarHelper.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Common\TraceLogger.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Common\Utils.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Common\ValidSelectedItemConverter.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Controls\CalculationResult.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Controls\CalculationResultAutomationPeer.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Controls\CalculatorButton.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Controls\FlipButtons.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Controls\HorizontalNoOverflowStackPanel.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Controls\KeyboardShortcutManager.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Controls\OperandTextBox.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Controls\OperatorTextBox.cs" />
|
||||
|
@ -72,6 +78,11 @@
|
|||
<Compile Include="$(MSBuildThisFileDirectory)Converters\ItemSizeToVisibilityConverter.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Converters\RadixToStringConverter.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Converters\VisibilityNegationConverter.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)DataLoaders\CurrencyDataLoader.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)DataLoaders\CurrencyHttpClient.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)DataLoaders\ICurrencyHttpClient.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)DataLoaders\UnitConverterDataConstants.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)DataLoaders\UnitConverterDataLoader.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)ViewModels\ApplicationViewModel.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)ViewModels\DateCalculatorViewModel.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)ViewModels\HistoryItemViewModel.cs" />
|
||||
|
@ -138,6 +149,7 @@
|
|||
<Compile Include="$(MSBuildThisFileDirectory)Views\UnitConverter.xaml.cs">
|
||||
<DependentUpon>UnitConverter.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="$(MSBuildThisFileDirectory)_adapters\StringExtensions.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Include="$(MSBuildThisFileDirectory)Styles.xaml">
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Windows.Foundation;
|
||||
|
@ -8,5 +9,9 @@ namespace WindowsCalculator.Shared.Common
|
|||
{
|
||||
class AlwaysSelectedCollectionView
|
||||
{
|
||||
public AlwaysSelectedCollectionView(IEnumerable result)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
62
src/Calculator.Shared/Common/Automation/NarratorNotifier.cs
Normal file
62
src/Calculator.Shared/Common/Automation/NarratorNotifier.cs
Normal file
|
@ -0,0 +1,62 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Windows.UI.Xaml;
|
||||
|
||||
namespace CalculatorApp.Common.Automation
|
||||
{
|
||||
public sealed partial class NarratorNotifier : DependencyObject
|
||||
{
|
||||
public static DependencyProperty AnnouncementProperty { get; } = DependencyProperty.RegisterAttached(
|
||||
"Announcement",
|
||||
typeof(NarratorAnnouncement),
|
||||
typeof(NarratorNotifier),
|
||||
new PropertyMetadata(default(NarratorAnnouncement), OnAnnouncementChanged));
|
||||
|
||||
public static NarratorAnnouncement GetAnnouncement(Windows.UI.Xaml.DependencyObject element)
|
||||
{
|
||||
return element.GetValue(AnnouncementProperty) as NarratorAnnouncement;
|
||||
}
|
||||
|
||||
public static void SetAnnouncement(Windows.UI.Xaml.DependencyObject element, NarratorAnnouncement value)
|
||||
{
|
||||
element.SetValue(AnnouncementProperty, value);
|
||||
}
|
||||
|
||||
public NarratorAnnouncement Announcement
|
||||
{
|
||||
get { return GetAnnouncement(this); }
|
||||
set { SetAnnouncement(this, value); }
|
||||
}
|
||||
|
||||
|
||||
//TODO UNO INarratorAnnouncementHost m_announcementHost;
|
||||
|
||||
public NarratorNotifier()
|
||||
{
|
||||
// TODO UNO
|
||||
// m_announcementHost = NarratorAnnouncementHostFactory.MakeHost();
|
||||
}
|
||||
|
||||
public void Announce(NarratorAnnouncement announcement)
|
||||
{
|
||||
// TODO UNO:
|
||||
//if (NarratorAnnouncement.IsValid(announcement) && m_announcementHost != null)
|
||||
//{
|
||||
// m_announcementHost.Announce(announcement);
|
||||
//}
|
||||
}
|
||||
|
||||
static void OnAnnouncementChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var instance = dependencyObject as NarratorNotifier;
|
||||
if (instance != null)
|
||||
{
|
||||
instance.Announce((NarratorAnnouncement)(e.NewValue));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
44
src/Calculator.Shared/Common/ConversionResultTaskHelper.cs
Normal file
44
src/Calculator.Shared/Common/ConversionResultTaskHelper.cs
Normal file
|
@ -0,0 +1,44 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CalculatorApp.Common
|
||||
{
|
||||
class ConversionResultTaskHelper
|
||||
{
|
||||
uint m_delay;
|
||||
CancellationTokenSource m_cts = new CancellationTokenSource();
|
||||
Action m_storedFunction;
|
||||
|
||||
public ConversionResultTaskHelper(uint delay, Action functionToRun)
|
||||
{
|
||||
m_delay = delay;
|
||||
m_storedFunction = functionToRun;
|
||||
|
||||
var delayTask = CompleteAfter(delay);
|
||||
}
|
||||
|
||||
~ConversionResultTaskHelper()
|
||||
{
|
||||
m_cts.Cancel();
|
||||
}
|
||||
|
||||
// Creates a task that completes after the specified delay.
|
||||
//
|
||||
// Taken from: How to: Create a Task that Completes After a Delay
|
||||
// https://msdn.microsoft.com/en-us/library/hh873170.aspx
|
||||
async Task CompleteAfter(uint timeout)
|
||||
{
|
||||
await Task.Delay(TimeSpan.FromMilliseconds(timeout));
|
||||
if (!m_cts.Token.IsCancellationRequested)
|
||||
{
|
||||
m_storedFunction();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -28,7 +28,7 @@ namespace CalculatorApp.Common
|
|||
|
||||
public sealed class LocalizationService
|
||||
{
|
||||
static string DefaultCurrencyCode = "USD";
|
||||
internal static string DefaultCurrencyCode = "USD";
|
||||
|
||||
|
||||
|
||||
|
@ -167,7 +167,7 @@ namespace CalculatorApp.Common
|
|||
}
|
||||
}
|
||||
|
||||
FlowDirection GetFlowDirection()
|
||||
public FlowDirection GetFlowDirection()
|
||||
{
|
||||
return m_flowDirection;
|
||||
}
|
||||
|
|
|
@ -335,7 +335,7 @@ namespace CalculatorApp
|
|||
return m_currencyTrailingDigits;
|
||||
}
|
||||
|
||||
int GetCurrencySymbolPrecedence()
|
||||
public int GetCurrencySymbolPrecedence()
|
||||
{
|
||||
return m_currencySymbolPrecedence;
|
||||
}
|
||||
|
|
|
@ -140,7 +140,7 @@ namespace CalculatorApp
|
|||
|
||||
public string AccessKey => m_accessKey;
|
||||
|
||||
bool SupportsNegative
|
||||
public bool SupportsNegative
|
||||
{
|
||||
get
|
||||
{
|
||||
|
@ -531,13 +531,13 @@ namespace CalculatorApp
|
|||
public CategoryGroupType GroupType { get => m_GroupType; private set { m_GroupType = value; RaisePropertyChanged("GroupType"); } }
|
||||
|
||||
|
||||
private ObservableCollection<NavCategory> m_Categories;
|
||||
public ObservableCollection<NavCategory> Categories { get => m_Categories; private set { m_Categories = value; RaisePropertyChanged("Categories"); } }
|
||||
private CalculatorObservableCollection<NavCategory> m_Categories;
|
||||
public CalculatorObservableCollection<NavCategory> Categories { get => m_Categories; private set { m_Categories = value; RaisePropertyChanged("Categories"); } }
|
||||
|
||||
|
||||
internal NavCategoryGroup(NavCategoryGroupInitializer groupInitializer)
|
||||
{
|
||||
m_Categories = new ObservableCollection<NavCategory>();
|
||||
m_Categories = new CalculatorObservableCollection<NavCategory>();
|
||||
m_GroupType = groupInitializer.type;
|
||||
|
||||
var resProvider = AppResourceProvider.GetInstance();
|
||||
|
@ -573,9 +573,9 @@ namespace CalculatorApp
|
|||
}
|
||||
}
|
||||
|
||||
public static ObservableCollection<NavCategoryGroup> CreateMenuOptions()
|
||||
public static CalculatorObservableCollection<NavCategoryGroup> CreateMenuOptions()
|
||||
{
|
||||
var menuOptions = new ObservableCollection<NavCategoryGroup>();
|
||||
var menuOptions = new CalculatorObservableCollection<NavCategoryGroup>();
|
||||
menuOptions.Add(CreateCalculatorCategory());
|
||||
menuOptions.Add(CreateConverterCategory());
|
||||
return menuOptions;
|
||||
|
@ -586,7 +586,7 @@ namespace CalculatorApp
|
|||
return new NavCategoryGroup(NavCategory.s_categoryGroupManifest[0].Value);
|
||||
}
|
||||
|
||||
static NavCategoryGroup CreateConverterCategory()
|
||||
public static NavCategoryGroup CreateConverterCategory()
|
||||
{
|
||||
return new NavCategoryGroup(NavCategory.s_categoryGroupManifest[1].Value);
|
||||
}
|
||||
|
|
68
src/Calculator.Shared/Common/NetworkManager.cs
Normal file
68
src/Calculator.Shared/Common/NetworkManager.cs
Normal file
|
@ -0,0 +1,68 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Windows.Networking.Connectivity;
|
||||
|
||||
namespace CalculatorApp
|
||||
{
|
||||
public enum NetworkAccessBehavior
|
||||
{
|
||||
Normal = 0,
|
||||
OptIn = 1,
|
||||
Offline = 2
|
||||
};
|
||||
|
||||
public delegate void NetworkBehaviorChangedHandler(NetworkAccessBehavior behavior);
|
||||
|
||||
public sealed class NetworkManager
|
||||
{
|
||||
public event NetworkBehaviorChangedHandler NetworkBehaviorChanged;
|
||||
|
||||
public NetworkManager()
|
||||
{
|
||||
NetworkInformation.NetworkStatusChanged += new NetworkStatusChangedEventHandler(OnNetworkStatusChange);
|
||||
}
|
||||
|
||||
~NetworkManager()
|
||||
{
|
||||
NetworkInformation.NetworkStatusChanged -= OnNetworkStatusChange;
|
||||
}
|
||||
|
||||
public static NetworkAccessBehavior GetNetworkAccessBehavior()
|
||||
{
|
||||
NetworkAccessBehavior behavior = NetworkAccessBehavior.Offline;
|
||||
ConnectionProfile connectionProfile = NetworkInformation.GetInternetConnectionProfile();
|
||||
if (connectionProfile != null)
|
||||
{
|
||||
NetworkConnectivityLevel connectivityLevel = connectionProfile.GetNetworkConnectivityLevel();
|
||||
if (connectivityLevel == NetworkConnectivityLevel.InternetAccess || connectivityLevel == NetworkConnectivityLevel.ConstrainedInternetAccess)
|
||||
{
|
||||
ConnectionCost connectionCost = connectionProfile.GetConnectionCost();
|
||||
behavior = ConvertCostInfoToBehavior(connectionCost);
|
||||
}
|
||||
}
|
||||
|
||||
return behavior;
|
||||
}
|
||||
|
||||
void OnNetworkStatusChange(object sender)
|
||||
{
|
||||
NetworkBehaviorChanged?.Invoke(GetNetworkAccessBehavior());
|
||||
}
|
||||
|
||||
// See app behavior guidelines at https://msdn.microsoft.com/en-us/library/windows/apps/xaml/jj835821(v=win.10).aspx
|
||||
static NetworkAccessBehavior ConvertCostInfoToBehavior(ConnectionCost connectionCost)
|
||||
{
|
||||
if (connectionCost.Roaming || connectionCost.OverDataLimit || connectionCost.NetworkCostType == NetworkCostType.Variable
|
||||
|| connectionCost.NetworkCostType == NetworkCostType.Fixed)
|
||||
{
|
||||
return NetworkAccessBehavior.OptIn;
|
||||
}
|
||||
|
||||
return NetworkAccessBehavior.Normal;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using Windows.Globalization;
|
||||
using CalculatorApp.Common;
|
||||
|
@ -63,7 +64,7 @@ namespace CalculatorApp
|
|||
public void LogWindowActivated() {}
|
||||
public void LogWindowLaunched() {}
|
||||
public void LogUserRequestedRefreshFailed() {}
|
||||
//public void LogConversionResult(std::wstring_view fromValue, std::wstring_view fromUnit, std::wstring_view toValue, std::wstring_view toUnit) {}
|
||||
public void LogConversionResult(string fromValue, string fromUnit, string toValue, string toUnit) {}
|
||||
public void LogAboutFlyoutOpened() {}
|
||||
public void LogNavBarOpened() {}
|
||||
public void LogViewClosingTelemetry(int i) {}
|
||||
|
@ -74,8 +75,8 @@ namespace CalculatorApp
|
|||
public void LogDateAddSubtractModeUsed(int windowId, bool isAddMode) {}
|
||||
public void LogDateClippedTimeDifferenceFound(Calendar today, DateTime clippedTime) {}
|
||||
|
||||
//public void LogStandardException(std::wstring_view functionName, _In_ const std::exception& e) {}
|
||||
//public void LogWinRTException(std::wstring_view functionName, _In_ winrt::hresult_error const& e) {}
|
||||
//public void LogPlatformException(std::wstring_view functionName, _In_ Platform::Exception ^ e) {}
|
||||
public void LogStandardException(Exception e, [CallerMemberName] string functionName = null) { }
|
||||
public void LogWinRTException(Exception e, [CallerMemberName] string functionName = null) { }
|
||||
public void LogPlatformException(Exception e, [CallerMemberName] string functionName = null) {}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Windows.Storage;
|
||||
using Windows.UI.Core;
|
||||
using Windows.UI.ViewManagement;
|
||||
|
||||
|
@ -31,5 +34,47 @@ namespace CalculatorApp
|
|||
{
|
||||
return !string.IsNullOrEmpty(input) && input.Last() == target;
|
||||
}
|
||||
}
|
||||
|
||||
public static void Swap<T>(ref T field1, ref T field2)
|
||||
{
|
||||
var tmp = field1;
|
||||
field1 = field2;
|
||||
field2 = tmp;
|
||||
}
|
||||
|
||||
public static bool IsDateTimeOlderThan(DateTime dateTime, long duration)
|
||||
{
|
||||
return dateTime + TimeSpan.FromTicks(duration) < DateTime.Now;
|
||||
}
|
||||
|
||||
public static async Task<string> ReadFileFromFolder(StorageFolder folder, string filename)
|
||||
{
|
||||
if (folder == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var filePath = Path.Combine(folder.Path, filename);
|
||||
using (var reader = new StreamReader(filePath))
|
||||
{
|
||||
return await reader.ReadToEndAsync();
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task WriteFileToFolder(StorageFolder folder, string filename, string contents, CreationCollisionOption colisionOption)
|
||||
{
|
||||
if (folder== null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var filePath = Path.Combine(folder.Path, filename);
|
||||
using (var writer = new StreamWriter(filePath, append: false))
|
||||
{
|
||||
await writer.WriteAsync(contents);
|
||||
}
|
||||
}
|
||||
|
||||
public static DateTime GetUniversalSystemTime() => DateTime.UtcNow;
|
||||
}
|
||||
}
|
||||
|
|
37
src/Calculator.Shared/Common/ValidSelectedItemConverter.cs
Normal file
37
src/Calculator.Shared/Common/ValidSelectedItemConverter.cs
Normal file
|
@ -0,0 +1,37 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Windows.UI.Xaml.Data;
|
||||
|
||||
namespace CalculatorApp.Common
|
||||
{
|
||||
public sealed class ValidSelectedItemConverter : IValueConverter
|
||||
{
|
||||
public ValidSelectedItemConverter()
|
||||
{
|
||||
}
|
||||
|
||||
public object Convert(object value, Type targetType, object parameter, string language)
|
||||
{
|
||||
// Pass through as we don't want to change the value from the source
|
||||
return value;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, string language)
|
||||
{
|
||||
if (value != null)
|
||||
{
|
||||
if (value is int i && i > 0)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
// Stop the binding if the object is null
|
||||
return Windows.UI.Xaml.DependencyProperty.UnsetValue;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -10,6 +10,7 @@ using Windows.UI.Xaml.Automation.Peers;
|
|||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Input;
|
||||
using Windows.UI.Xaml.Media;
|
||||
using CalculatorApp.ViewModel;
|
||||
|
||||
namespace CalculatorApp
|
||||
{
|
||||
|
@ -17,7 +18,7 @@ namespace CalculatorApp
|
|||
{
|
||||
public delegate void SelectedEventHandler(object sender);
|
||||
|
||||
public sealed partial class CalculationResult : Windows.UI.Xaml.Controls.Control
|
||||
public sealed partial class CalculationResult : Windows.UI.Xaml.Controls.Control, IActivatable
|
||||
{
|
||||
public Visibility ExpressionVisibility
|
||||
{
|
||||
|
@ -130,7 +131,7 @@ namespace CalculatorApp
|
|||
public static readonly DependencyProperty IsOperatorCommandProperty =
|
||||
DependencyProperty.Register("IsOperatorCommand", typeof(bool), typeof(CalculationResult), new PropertyMetadata(false));
|
||||
|
||||
event SelectedEventHandler Selected;
|
||||
public event SelectedEventHandler Selected;
|
||||
|
||||
|
||||
private Windows.UI.Xaml.Controls.ScrollViewer m_textContainer;
|
||||
|
@ -163,7 +164,7 @@ namespace CalculatorApp
|
|||
m_haveCalculatedMax = false;
|
||||
}
|
||||
|
||||
string GetRawDisplayValue()
|
||||
public string GetRawDisplayValue()
|
||||
{
|
||||
string rawValue = null;
|
||||
|
||||
|
@ -298,7 +299,7 @@ namespace CalculatorApp
|
|||
}
|
||||
}
|
||||
|
||||
void UpdateTextState()
|
||||
public void UpdateTextState()
|
||||
{
|
||||
if ((m_textContainer == null) || (m_textBlock == null))
|
||||
{
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Windows.Foundation;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
|
||||
namespace CalculatorApp.Controls
|
||||
{
|
||||
public partial class HorizontalNoOverflowStackPanel : Panel
|
||||
{
|
||||
// TODO UNO: DEPENDENCY_PROPERTY_OWNER(HorizontalNoOverflowStackPanel);
|
||||
|
||||
protected override Size MeasureOverride(Size availableSize)
|
||||
{
|
||||
double maxHeight = 0;
|
||||
double width = 0;
|
||||
foreach (UIElement child in Children)
|
||||
{
|
||||
child.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
|
||||
maxHeight = Math.Max(maxHeight, child.DesiredSize.Height);
|
||||
width += child.DesiredSize.Width;
|
||||
}
|
||||
return new Size(Math.Min(width, availableSize.Width), Math.Min(availableSize.Height, maxHeight));
|
||||
}
|
||||
|
||||
protected virtual bool ShouldPrioritizeLastItem()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
protected override Size ArrangeOverride(Size finalSize)
|
||||
{
|
||||
if (Children.Count == 0)
|
||||
{
|
||||
return finalSize;
|
||||
}
|
||||
|
||||
double posX = 0;
|
||||
var lastChild = (UIElement)Children.Last();
|
||||
double lastChildWidth = 0;
|
||||
if (Children.Count > 2 && ShouldPrioritizeLastItem())
|
||||
{
|
||||
lastChildWidth = lastChild.DesiredSize.Width;
|
||||
}
|
||||
foreach (UIElement item in Children)
|
||||
{
|
||||
var widthAvailable = finalSize.Width - posX;
|
||||
if (item != lastChild)
|
||||
{
|
||||
widthAvailable -= lastChildWidth;
|
||||
}
|
||||
double itemWidth = item.DesiredSize.Width;
|
||||
if (widthAvailable > 0 && itemWidth <= widthAvailable)
|
||||
{
|
||||
// stack the items horizontally (left to right)
|
||||
item.Arrange(new Rect(posX, 0, itemWidth, finalSize.Height));
|
||||
posX += item.RenderSize.Width;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Not display the item
|
||||
item.Arrange(new Rect(0, 0, 0, 0));
|
||||
}
|
||||
}
|
||||
return finalSize;
|
||||
}
|
||||
};
|
||||
}
|
|
@ -1,3 +1,6 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
@ -5,6 +8,7 @@ using Windows.UI.Xaml;
|
|||
using Windows.UI.Xaml.Automation;
|
||||
using Windows.UI.Xaml.Automation.Peers;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using CalculatorApp.ViewModel;
|
||||
|
||||
namespace CalculatorApp.Controls
|
||||
{
|
||||
|
@ -20,13 +24,12 @@ namespace CalculatorApp.Controls
|
|||
{
|
||||
base.PrepareContainerForItemOverride(element, item);
|
||||
|
||||
// UNO TODO
|
||||
//var supplementaryResult = (SupplementaryResult)(item);
|
||||
//if (supplementaryResult)
|
||||
//{
|
||||
// AutomationProperties.SetName(element, supplementaryResult.GetLocalizedAutomationName());
|
||||
//}
|
||||
}
|
||||
var supplementaryResult = (SupplementaryResult)(item);
|
||||
if (supplementaryResult != null)
|
||||
{
|
||||
AutomationProperties.SetName(element, supplementaryResult.GetLocalizedAutomationName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed partial class SupplementaryContentPresenter : ContentPresenter
|
||||
|
|
|
@ -1,39 +1,44 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using WindowsCalculator.Shared.Common;
|
||||
|
||||
namespace CalculatorApp
|
||||
{
|
||||
namespace Common
|
||||
{
|
||||
//class AlwaysSelectedCollectionViewConverter : Windows.UI.Xaml.Data.IValueConverter
|
||||
//{
|
||||
// public AlwaysSelectedCollectionViewConverter()
|
||||
// {
|
||||
// }
|
||||
class AlwaysSelectedCollectionViewConverter : Windows.UI.Xaml.Data.IValueConverter
|
||||
{
|
||||
public AlwaysSelectedCollectionViewConverter()
|
||||
{
|
||||
}
|
||||
|
||||
// object Convert(
|
||||
// object value,
|
||||
// Type targetType,
|
||||
// object parameter,
|
||||
// string language)
|
||||
// {
|
||||
// var result = (IEnumerable)(value);
|
||||
// if (result)
|
||||
// {
|
||||
// return new AlwaysSelectedCollectionView(result);
|
||||
// }
|
||||
// return Windows.UI.Xaml.DependencyProperty.UnsetValue; // Can't convert
|
||||
// }
|
||||
public object Convert(
|
||||
object value,
|
||||
Type targetType,
|
||||
object parameter,
|
||||
string language)
|
||||
{
|
||||
var result = value as IEnumerable;
|
||||
if (result != null)
|
||||
{
|
||||
return new AlwaysSelectedCollectionView(result);
|
||||
}
|
||||
return Windows.UI.Xaml.DependencyProperty.UnsetValue; // Can't convert
|
||||
}
|
||||
|
||||
// object ConvertBack(
|
||||
// object value,
|
||||
// Type targetType,
|
||||
// object parameter,
|
||||
// string language)
|
||||
// {
|
||||
// return Windows.UI.Xaml.DependencyProperty.UnsetValue;
|
||||
// }
|
||||
//}
|
||||
}
|
||||
public object ConvertBack(
|
||||
object value,
|
||||
Type targetType,
|
||||
object parameter,
|
||||
string language)
|
||||
{
|
||||
return Windows.UI.Xaml.DependencyProperty.UnsetValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,7 @@
|
|||
using System;
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Windows.UI.Xaml.Interop;
|
||||
|
@ -6,7 +9,7 @@ using Windows.Foundation.Metadata;
|
|||
using Windows.UI.Xaml.Data;
|
||||
using Windows.UI.Xaml;
|
||||
|
||||
namespace CalculatorApp.Converters
|
||||
namespace CalculatorApp.Common
|
||||
{
|
||||
[WebHostHidden]
|
||||
public sealed class VisibilityNegationConverter : IValueConverter
|
||||
|
|
792
src/Calculator.Shared/DataLoaders/CurrencyDataLoader.cs
Normal file
792
src/Calculator.Shared/DataLoaders/CurrencyDataLoader.cs
Normal file
|
@ -0,0 +1,792 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Windows.Data.Json;
|
||||
using Windows.Foundation.Collections;
|
||||
using Windows.Globalization.DateTimeFormatting;
|
||||
using Windows.Storage;
|
||||
using Windows.System.UserProfile;
|
||||
using Windows.UI.Core;
|
||||
using CalculatorApp.Common;
|
||||
using CalculatorApp.DataLoaders;
|
||||
using UCM = UnitConversionManager;
|
||||
using CurrencyRatioMap = System.Collections.Generic.Dictionary<string, UnitConversionManager.CurrencyRatio>;
|
||||
using SelectedUnits = System.Collections.Generic.KeyValuePair<string, string>;
|
||||
using CategorySelectionInitializer = System.Tuple<CalculatorApp.CalculatorList<UnitConversionManager.Unit>, UnitConversionManager.Unit, UnitConversionManager.Unit>;
|
||||
using UnitToUnitToConversionDataMap = System.Collections.Generic.Dictionary<UnitConversionManager.Unit, System.Collections.Generic.Dictionary<UnitConversionManager.Unit, UnitConversionManager.ConversionData>>;
|
||||
using CategoryToUnitVectorMap = System.Collections.Generic.Dictionary<UnitConversionManager.Category, CalculatorApp.CalculatorList<UnitConversionManager.Unit>>;
|
||||
|
||||
namespace CalculatorApp.ViewModel
|
||||
{
|
||||
public enum CurrencyLoadStatus
|
||||
{
|
||||
NotLoaded = 0,
|
||||
FailedToLoad = 1,
|
||||
LoadedFromCache = 2,
|
||||
LoadedFromWeb = 3
|
||||
}
|
||||
|
||||
public static class UnitConverterResourceKeys
|
||||
{
|
||||
public const string CurrencyUnitFromKey = CurrencyDataLoader.CURRENCY_UNIT_FROM_KEY;
|
||||
public const string CurrencyUnitToKey = CurrencyDataLoader.CURRENCY_UNIT_TO_KEY;
|
||||
}
|
||||
|
||||
public static class CurrencyDataLoaderConstants
|
||||
{
|
||||
public const string CacheTimestampKey = CurrencyDataLoader.CACHE_TIMESTAMP_KEY;
|
||||
public const string CacheLangcodeKey = CurrencyDataLoader.CACHE_LANGCODE_KEY;
|
||||
public const string CacheDelimiter = CurrencyDataLoader.CACHE_DELIMITER;
|
||||
public const string StaticDataFilename = CurrencyDataLoader.STATIC_DATA_FILENAME;
|
||||
public const string AllRatiosDataFilename = CurrencyDataLoader.ALL_RATIOS_DATA_FILENAME;
|
||||
public const long DayDuration = CurrencyDataLoader.DAY_DURATION;
|
||||
}
|
||||
|
||||
struct CurrencyUnitMetadata
|
||||
{
|
||||
public CurrencyUnitMetadata(string s)
|
||||
{
|
||||
symbol = s;
|
||||
}
|
||||
|
||||
public string symbol;
|
||||
};
|
||||
|
||||
public class CurrencyDataLoader : UCM.IConverterDataLoader, UCM.ICurrencyConverterDataLoader
|
||||
{
|
||||
//private:
|
||||
string m_responseLanguage;
|
||||
CalculatorApp.DataLoaders.ICurrencyHttpClient m_client;
|
||||
|
||||
bool m_isRtlLanguage;
|
||||
|
||||
//Mutex m_currencyUnitsMutex;
|
||||
object m_currencyUnitsMutex = new object();
|
||||
CalculatorList<UCM.Unit> m_currencyUnits = new CalculatorList<UCM.Unit>();
|
||||
UnitToUnitToConversionDataMap m_currencyRatioMap = new UnitToUnitToConversionDataMap(EqualityComparer<UCM.Unit>.Default);
|
||||
Dictionary<UCM.Unit, CurrencyUnitMetadata> m_currencyMetadata = new Dictionary<UCM.Unit, CurrencyUnitMetadata>(EqualityComparer<UCM.Unit>.Default);
|
||||
|
||||
UCM.IViewModelCurrencyCallback m_vmCallback;
|
||||
|
||||
Windows.Globalization.NumberFormatting.DecimalFormatter m_ratioFormatter;
|
||||
string m_ratioFormat;
|
||||
DateTime m_cacheTimestamp;
|
||||
string m_timestampFormat;
|
||||
|
||||
CurrencyLoadStatus m_loadStatus;
|
||||
|
||||
CalculatorApp.NetworkManager m_networkManager;
|
||||
|
||||
CalculatorApp.NetworkAccessBehavior m_networkAccessBehavior;
|
||||
|
||||
//Windows.Foundation.EventRegistrationToken m_networkBehaviorToken;
|
||||
bool m_meteredOverrideSet;
|
||||
|
||||
internal const string CURRENCY_UNIT_FROM_KEY = "CURRENCY_UNIT_FROM_KEY";
|
||||
internal const string CURRENCY_UNIT_TO_KEY = "CURRENCY_UNIT_TO_KEY";
|
||||
|
||||
// Calculate number of 100-nanosecond intervals-per-day
|
||||
// (1 interval/100 nanosecond)(100 nanosecond/1e-7 s)(60 s/1 min)(60 min/1 hr)(24 hr/1 day) = (interval/day)
|
||||
internal const long DAY_DURATION = 1L * 60 * 60 * 24 * 10000000;
|
||||
internal const long WEEK_DURATION = DAY_DURATION * 7;
|
||||
|
||||
static int FORMATTER_DIGIT_COUNT = 4;
|
||||
|
||||
internal const string CACHE_TIMESTAMP_KEY = "CURRENCY_CONVERTER_TIMESTAMP";
|
||||
internal const string CACHE_LANGCODE_KEY = "CURRENCY_CONVERTER_LANGCODE";
|
||||
internal const string CACHE_DELIMITER = "%";
|
||||
|
||||
internal const string STATIC_DATA_FILENAME = "CURRENCY_CONVERTER_STATIC_DATA.txt";
|
||||
|
||||
private static string[] STATIC_DATA_PROPERTIES =
|
||||
{
|
||||
"CountryCode",
|
||||
"CountryName",
|
||||
"CurrencyCode",
|
||||
"CurrencyName",
|
||||
"CurrencySymbol"
|
||||
};
|
||||
|
||||
internal const string ALL_RATIOS_DATA_FILENAME = "CURRENCY_CONVERTER_ALL_RATIOS_DATA.txt";
|
||||
internal const string RATIO_KEY = "Rt";
|
||||
internal const string CURRENCY_CODE_KEY = "An";
|
||||
internal static string[] ALL_RATIOS_DATA_PROPERTIES = {RATIO_KEY, CURRENCY_CODE_KEY};
|
||||
|
||||
static string DEFAULT_FROM_TO_CURRENCY_FILE_URI = "ms-appx:///DataLoaders/DefaultFromToCurrency.json";
|
||||
static string FROM_KEY = "from";
|
||||
static string TO_KEY = "to";
|
||||
|
||||
// Fallback default values.
|
||||
static string DEFAULT_FROM_CURRENCY = DefaultCurrencyCode;
|
||||
static string DEFAULT_TO_CURRENCY = "EUR";
|
||||
|
||||
private static string DefaultCurrencyCode = LocalizationService.DefaultCurrencyCode;
|
||||
|
||||
public CurrencyDataLoader(ICurrencyHttpClient client)
|
||||
{
|
||||
this.m_client = client;
|
||||
;
|
||||
this.m_loadStatus = CurrencyLoadStatus.NotLoaded;
|
||||
this.m_responseLanguage = "en-US";
|
||||
this.m_ratioFormat = "";
|
||||
this.m_timestampFormat = "";
|
||||
this.m_networkManager = new NetworkManager();
|
||||
this.m_meteredOverrideSet = false;
|
||||
|
||||
|
||||
if (GlobalizationPreferences.Languages.Count > 0)
|
||||
{
|
||||
m_responseLanguage = GlobalizationPreferences.Languages[0];
|
||||
}
|
||||
|
||||
if (m_client != null)
|
||||
{
|
||||
m_client.SetSourceCurrencyCode(DefaultCurrencyCode);
|
||||
m_client.SetResponseLanguage(m_responseLanguage);
|
||||
}
|
||||
|
||||
if (CoreWindow.GetForCurrentThread() != null)
|
||||
{
|
||||
// Must have a CoreWindow to access the resource context.
|
||||
m_isRtlLanguage = LocalizationService.GetInstance().IsRtlLayout();
|
||||
}
|
||||
|
||||
m_ratioFormatter = LocalizationService.GetRegionalSettingsAwareDecimalFormatter();
|
||||
m_ratioFormatter.IsGrouped = true;
|
||||
m_ratioFormatter.IsDecimalPointAlwaysDisplayed = true;
|
||||
m_ratioFormatter.FractionDigits = FORMATTER_DIGIT_COUNT;
|
||||
|
||||
m_ratioFormat = AppResourceProvider.GetInstance().GetResourceString("CurrencyFromToRatioFormat");
|
||||
m_timestampFormat = AppResourceProvider.GetInstance().GetResourceString("CurrencyTimestampFormat");
|
||||
}
|
||||
|
||||
~CurrencyDataLoader()
|
||||
{
|
||||
UnregisterForNetworkBehaviorChanges();
|
||||
}
|
||||
|
||||
void UnregisterForNetworkBehaviorChanges()
|
||||
{
|
||||
m_networkManager.NetworkBehaviorChanged -= OnNetworkBehaviorChanged;
|
||||
}
|
||||
|
||||
void RegisterForNetworkBehaviorChanges()
|
||||
{
|
||||
UnregisterForNetworkBehaviorChanges();
|
||||
|
||||
m_networkManager.NetworkBehaviorChanged += new NetworkBehaviorChangedHandler(OnNetworkBehaviorChanged);
|
||||
|
||||
OnNetworkBehaviorChanged(NetworkManager.GetNetworkAccessBehavior());
|
||||
}
|
||||
|
||||
void OnNetworkBehaviorChanged(NetworkAccessBehavior newBehavior)
|
||||
{
|
||||
m_networkAccessBehavior = newBehavior;
|
||||
if (m_vmCallback != null)
|
||||
{
|
||||
m_vmCallback.NetworkBehaviorChanged((int)(m_networkAccessBehavior));
|
||||
}
|
||||
}
|
||||
|
||||
bool LoadFinished()
|
||||
{
|
||||
return m_loadStatus != CurrencyLoadStatus.NotLoaded;
|
||||
}
|
||||
|
||||
bool LoadedFromCache()
|
||||
{
|
||||
return m_loadStatus == CurrencyLoadStatus.LoadedFromCache;
|
||||
}
|
||||
|
||||
bool LoadedFromWeb()
|
||||
{
|
||||
return m_loadStatus == CurrencyLoadStatus.LoadedFromWeb;
|
||||
}
|
||||
|
||||
void ResetLoadStatus()
|
||||
{
|
||||
m_loadStatus = CurrencyLoadStatus.NotLoaded;
|
||||
}
|
||||
|
||||
public async void LoadData()
|
||||
{
|
||||
RegisterForNetworkBehaviorChanges();
|
||||
|
||||
if (!LoadFinished())
|
||||
{
|
||||
var loadFunctions = new Func<Task<bool>>[]
|
||||
{
|
||||
TryLoadDataFromCacheAsync,
|
||||
TryLoadDataFromWebAsync
|
||||
};
|
||||
|
||||
bool didLoad = false;
|
||||
foreach (var f in loadFunctions)
|
||||
{
|
||||
didLoad = await f();
|
||||
if (didLoad)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
UpdateDisplayedTimestamp();
|
||||
NotifyDataLoadFinished(didLoad);
|
||||
}
|
||||
}
|
||||
|
||||
public CalculatorList<UCM.Category> LoadOrderedCategories()
|
||||
{
|
||||
// This function should not be called
|
||||
// The model will use the categories from UnitConverterDataLoader
|
||||
return new CalculatorList<UCM.Category>();
|
||||
}
|
||||
|
||||
public CalculatorList<UCM.Unit> LoadOrderedUnits(UCM.Category category)
|
||||
{
|
||||
lock (m_currencyUnitsMutex)
|
||||
{
|
||||
return m_currencyUnits;
|
||||
}
|
||||
}
|
||||
|
||||
public Dictionary<UCM.Unit, UCM.ConversionData> LoadOrderedRatios(UCM.Unit unit)
|
||||
{
|
||||
lock (m_currencyUnitsMutex) ;
|
||||
{
|
||||
return m_currencyRatioMap[unit];
|
||||
}
|
||||
}
|
||||
|
||||
public bool SupportsCategory(UCM.Category target)
|
||||
{
|
||||
int currencyId = NavCategory.Serialize(ViewMode.Currency);
|
||||
return target.id == currencyId;
|
||||
}
|
||||
|
||||
public void SetViewModelCallback(UCM.IViewModelCurrencyCallback callback)
|
||||
{
|
||||
m_vmCallback = callback;
|
||||
OnNetworkBehaviorChanged(m_networkAccessBehavior);
|
||||
}
|
||||
|
||||
public KeyValuePair<string, string> GetCurrencySymbols(UCM.Unit unit1, UCM.Unit unit2)
|
||||
{
|
||||
lock (m_currencyUnitsMutex)
|
||||
{
|
||||
|
||||
string symbol1 = "";
|
||||
string symbol2 = "";
|
||||
|
||||
if (m_currencyMetadata.TryGetValue(unit1, out var itr1) && m_currencyMetadata.TryGetValue(unit2, out var itr2))
|
||||
{
|
||||
symbol1 = itr1.symbol;
|
||||
symbol2 = itr2.symbol;
|
||||
}
|
||||
|
||||
return new KeyValuePair<string, string>(symbol1, symbol2);
|
||||
}
|
||||
}
|
||||
|
||||
public KeyValuePair<string, string> GetCurrencyRatioEquality(UCM.Unit unit1, UCM.Unit unit2)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (m_currencyRatioMap.TryGetValue(unit1, out var ratioMap))
|
||||
{
|
||||
if (ratioMap.TryGetValue(unit2, out var iter2))
|
||||
{
|
||||
var ratio = iter2.ratio;
|
||||
|
||||
// Round the ratio to FORMATTER_DIGIT_COUNT digits using int math.
|
||||
// Ex: to round 1.23456 to three digits, use
|
||||
// ((int) 1.23456 * (10^3)) / (10^3)
|
||||
double scale = Math.Pow(10, FORMATTER_DIGIT_COUNT);
|
||||
double rounded = (int)(ratio * (int)(scale)) / scale;
|
||||
|
||||
string digitSymbol = LocalizationSettings.GetInstance().GetDigitSymbolFromEnUsDigit('1').ToString();
|
||||
string roundedFormat = m_ratioFormatter.Format(rounded);
|
||||
|
||||
string ratioString = LocalizationStringUtil.GetLocalizedString(
|
||||
m_ratioFormat,
|
||||
digitSymbol,
|
||||
unit1.abbreviation,
|
||||
roundedFormat,
|
||||
unit2.abbreviation);
|
||||
|
||||
string accessibleRatioString = LocalizationStringUtil.GetLocalizedString(
|
||||
m_ratioFormat,
|
||||
digitSymbol,
|
||||
unit1.accessibleName,
|
||||
roundedFormat,
|
||||
unit2.accessibleName);
|
||||
|
||||
return new KeyValuePair<string, string>(ratioString, accessibleRatioString);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
return new KeyValuePair<string, string>("", "");
|
||||
}
|
||||
|
||||
#pragma optimize("", off) // Turn off optimizations to work around DevDiv 393321
|
||||
public async Task<bool> TryLoadDataFromCacheAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
ResetLoadStatus();
|
||||
|
||||
var localSettings = ApplicationData.Current.LocalSettings;
|
||||
if (localSettings == null || !localSettings.Values.ContainsKey(CurrencyDataLoaderConstants.CacheTimestampKey))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool loadComplete = false;
|
||||
m_cacheTimestamp = DateTime.Parse((string)localSettings.Values[CurrencyDataLoaderConstants.CacheTimestampKey]);
|
||||
if (Utils.IsDateTimeOlderThan(m_cacheTimestamp, DAY_DURATION) && m_networkAccessBehavior == NetworkAccessBehavior.Normal)
|
||||
{
|
||||
loadComplete = await TryLoadDataFromWebAsync();
|
||||
}
|
||||
|
||||
if (!loadComplete)
|
||||
{
|
||||
loadComplete = await TryFinishLoadFromCacheAsync();
|
||||
}
|
||||
|
||||
return loadComplete;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
TraceLogger.GetInstance().LogStandardException(e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<bool> TryFinishLoadFromCacheAsync()
|
||||
{
|
||||
var localSettings = ApplicationData.Current.LocalSettings;
|
||||
if (localSettings == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!localSettings.Values.ContainsKey(CurrencyDataLoaderConstants.CacheLangcodeKey) || !((string)localSettings.Values[CurrencyDataLoaderConstants.CacheLangcodeKey]).Equals(m_responseLanguage))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
StorageFolder localCacheFolder = ApplicationData.Current.LocalCacheFolder;
|
||||
if (localCacheFolder == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
string staticDataResponse = await Utils.ReadFileFromFolder(localCacheFolder, CurrencyDataLoaderConstants.StaticDataFilename);
|
||||
string allRatiosResponse = await Utils.ReadFileFromFolder(localCacheFolder, CurrencyDataLoaderConstants.AllRatiosDataFilename);
|
||||
|
||||
CalculatorList<UCM.CurrencyStaticData> staticData = new CalculatorList<UCM.CurrencyStaticData>();
|
||||
CurrencyRatioMap ratioMap = new CurrencyRatioMap();
|
||||
|
||||
bool didParse = TryParseWebResponses(staticDataResponse, allRatiosResponse, staticData, ratioMap);
|
||||
if (!didParse)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_loadStatus = CurrencyLoadStatus.LoadedFromCache;
|
||||
await FinalizeUnits(staticData, ratioMap);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public async Task<bool> TryLoadDataFromWebAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
ResetLoadStatus();
|
||||
|
||||
if (m_client == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_networkAccessBehavior == NetworkAccessBehavior.Offline || (m_networkAccessBehavior == NetworkAccessBehavior.OptIn && !m_meteredOverrideSet))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
String staticDataResponse = await m_client.GetCurrencyMetadata();
|
||||
String allRatiosResponse = await m_client.GetCurrencyRatios();
|
||||
if (staticDataResponse == null || allRatiosResponse == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
CalculatorList<UCM.CurrencyStaticData> staticData = new CalculatorList<UCM.CurrencyStaticData>();
|
||||
CurrencyRatioMap ratioMap = new CurrencyRatioMap();
|
||||
|
||||
bool didParse = TryParseWebResponses(staticDataResponse, allRatiosResponse, staticData, ratioMap);
|
||||
if (!didParse)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set the timestamp before saving it below.
|
||||
m_cacheTimestamp = Utils.GetUniversalSystemTime();
|
||||
|
||||
try
|
||||
{
|
||||
CalculatorList<KeyValuePair<string, string>> cachedFiles = new CalculatorList<KeyValuePair<string, string>>
|
||||
{
|
||||
new KeyValuePair<string, string>(CurrencyDataLoaderConstants.StaticDataFilename, staticDataResponse),
|
||||
new KeyValuePair<string, string>(CurrencyDataLoaderConstants.AllRatiosDataFilename, allRatiosResponse)
|
||||
};
|
||||
|
||||
StorageFolder localCacheFolder = ApplicationData.Current.LocalCacheFolder;
|
||||
foreach (var fileInfo in cachedFiles)
|
||||
{
|
||||
await Utils.WriteFileToFolder(localCacheFolder, fileInfo.Key, fileInfo.Value, CreationCollisionOption.ReplaceExisting);
|
||||
}
|
||||
|
||||
SaveLangCodeAndTimestamp();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// If we fail to save to cache it's okay, we should still continue.
|
||||
}
|
||||
|
||||
m_loadStatus = CurrencyLoadStatus.LoadedFromWeb;
|
||||
await FinalizeUnits(staticData, ratioMap);
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
TraceLogger.GetInstance().LogStandardException(e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<bool> TryLoadDataFromWebOverrideAsync()
|
||||
{
|
||||
m_meteredOverrideSet = true;
|
||||
bool didLoad = await TryLoadDataFromWebAsync();
|
||||
if (!didLoad)
|
||||
{
|
||||
m_loadStatus = CurrencyLoadStatus.FailedToLoad;
|
||||
TraceLogger.GetInstance().LogUserRequestedRefreshFailed();
|
||||
}
|
||||
|
||||
return didLoad;
|
||||
}
|
||||
|
||||
bool TryParseWebResponses(
|
||||
String staticDataJson,
|
||||
String allRatiosJson,
|
||||
CalculatorList<UCM.CurrencyStaticData> staticData,
|
||||
CurrencyRatioMap allRatiosData)
|
||||
{
|
||||
return TryParseStaticData(staticDataJson, staticData) && TryParseAllRatiosData(allRatiosJson, allRatiosData);
|
||||
}
|
||||
|
||||
bool TryParseStaticData(String rawJson, CalculatorList<UCM.CurrencyStaticData> staticData)
|
||||
{
|
||||
JsonArray data = null;
|
||||
if (!JsonArray.TryParse(rawJson, out data))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
string countryCode = "";
|
||||
string countryName = "";
|
||||
string currencyCode = "";
|
||||
string currencyName = "";
|
||||
string currencySymbol = "";
|
||||
|
||||
string[] values = {countryCode, countryName, currencyCode, currencyName, currencySymbol};
|
||||
|
||||
Debug.Assert(values.Length == STATIC_DATA_PROPERTIES.Length);
|
||||
staticData.Clear();
|
||||
for (int i = 0; i < data.Count; i++)
|
||||
{
|
||||
JsonObject obj = data[i].GetObject();
|
||||
|
||||
countryCode = obj.GetNamedString(STATIC_DATA_PROPERTIES[0]);
|
||||
countryName = obj.GetNamedString(STATIC_DATA_PROPERTIES[1]);
|
||||
currencyCode = obj.GetNamedString(STATIC_DATA_PROPERTIES[2]);
|
||||
currencyName = obj.GetNamedString(STATIC_DATA_PROPERTIES[3]);
|
||||
currencySymbol = obj.GetNamedString(STATIC_DATA_PROPERTIES[4]);
|
||||
|
||||
staticData.Add(new UCM.CurrencyStaticData(countryCode, countryName, currencyCode, currencyName, currencySymbol));
|
||||
}
|
||||
|
||||
// TODO - MSFT 8533667: this sort will be replaced by a WinRT call to sort localized strings
|
||||
staticData.Sort((UCM.CurrencyStaticData unit1, UCM.CurrencyStaticData unit2) => { return unit1.countryName.CompareTo(unit2.countryName) < 0; });
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool TryParseAllRatiosData(String rawJson, CurrencyRatioMap allRatios)
|
||||
{
|
||||
JsonArray data = null;
|
||||
if (!JsonArray.TryParse(rawJson, out data))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
string sourceCurrencyCode = DefaultCurrencyCode;
|
||||
|
||||
allRatios.Clear();
|
||||
for (int i = 0; i < data.Count; i++)
|
||||
{
|
||||
JsonObject obj = data[i].GetObject();
|
||||
|
||||
// Rt is ratio, An is target currency ISO code.
|
||||
double relativeRatio = obj.GetNamedNumber(RATIO_KEY);
|
||||
string targetCurrencyCode = obj.GetNamedString(CURRENCY_CODE_KEY);
|
||||
|
||||
allRatios.Add(targetCurrencyCode, new UCM.CurrencyRatio(relativeRatio, sourceCurrencyCode, targetCurrencyCode));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// FinalizeUnits
|
||||
//
|
||||
// There are a few ways we can get the data needed for Currency Converter, including from cache or from web.
|
||||
// This function accepts the data from any source, and acts as a 'last-steps' for the converter to be ready.
|
||||
// This includes identifying which units will be selected and building the map of currency ratios.
|
||||
public async Task FinalizeUnits(CalculatorList<UCM.CurrencyStaticData> staticData, CurrencyRatioMap ratioMap)
|
||||
{
|
||||
Dictionary<int, KeyValuePair<UCM.Unit, double>> idToUnit = new Dictionary<int, KeyValuePair<UCM.Unit, double>>();
|
||||
|
||||
SelectedUnits defaultCurrencies = await GetDefaultFromToCurrency();
|
||||
string fromCurrency = defaultCurrencies.Key;
|
||||
string toCurrency = defaultCurrencies.Value;
|
||||
|
||||
lock (m_currencyUnitsMutex)
|
||||
{
|
||||
|
||||
int i = 1;
|
||||
m_currencyUnits.Clear();
|
||||
m_currencyMetadata.Clear();
|
||||
bool isConversionSourceSet = false;
|
||||
bool isConversionTargetSet = false;
|
||||
foreach (UCM.CurrencyStaticData currencyUnit in staticData)
|
||||
{
|
||||
if (ratioMap.TryGetValue(currencyUnit.currencyCode, out var itr) && itr.ratio > 0)
|
||||
{
|
||||
int id = (int)(UnitConverterUnits.UnitEnd + i);
|
||||
|
||||
bool isConversionSource = (fromCurrency == currencyUnit.currencyCode);
|
||||
isConversionSourceSet = isConversionSourceSet || isConversionSource;
|
||||
|
||||
bool isConversionTarget = (toCurrency == currencyUnit.currencyCode);
|
||||
isConversionTargetSet = isConversionTargetSet || isConversionTarget;
|
||||
|
||||
UCM.Unit unit = new UCM.Unit(
|
||||
id, // id
|
||||
currencyUnit.currencyName, // currencyName
|
||||
currencyUnit.countryName, // countryName
|
||||
currencyUnit.currencyCode, // abbreviation
|
||||
m_isRtlLanguage, // isRtlLanguage
|
||||
isConversionSource, // isConversionSource
|
||||
isConversionTarget // isConversionTarget
|
||||
);
|
||||
|
||||
m_currencyUnits.PushBack(unit);
|
||||
m_currencyMetadata.Add(unit, new CurrencyUnitMetadata(currencyUnit.currencySymbol));
|
||||
idToUnit.Add(unit.id, new KeyValuePair<UCM.Unit, double>(unit, itr.ratio));
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isConversionSourceSet || !isConversionTargetSet)
|
||||
{
|
||||
GuaranteeSelectedUnits();
|
||||
defaultCurrencies = new SelectedUnits(DEFAULT_FROM_CURRENCY, DEFAULT_TO_CURRENCY);
|
||||
}
|
||||
|
||||
m_currencyRatioMap.Clear();
|
||||
foreach (var unit in m_currencyUnits)
|
||||
{
|
||||
Dictionary<UCM.Unit, UCM.ConversionData> conversions = new Dictionary<UCM.Unit, UCM.ConversionData>(EqualityComparer<UCM.Unit>.Default);
|
||||
double unitFactor = idToUnit[unit.id].Value;
|
||||
foreach (var itr in idToUnit)
|
||||
{
|
||||
UCM.Unit targetUnit = (itr.Value).Key;
|
||||
double conversionRatio = (itr.Value).Value;
|
||||
UCM.ConversionData parsedData = new UCM.ConversionData(1.0, 0.0, false);
|
||||
Debug.Assert(unitFactor > 0); // divide by zero assert
|
||||
parsedData.ratio = conversionRatio / unitFactor;
|
||||
conversions.Add(targetUnit, parsedData);
|
||||
}
|
||||
|
||||
m_currencyRatioMap.Add(unit, conversions);
|
||||
}
|
||||
} // unlocked m_currencyUnitsMutex
|
||||
|
||||
SaveSelectedUnitsToLocalSettings(defaultCurrencies);
|
||||
}
|
||||
|
||||
|
||||
void GuaranteeSelectedUnits()
|
||||
{
|
||||
bool isConversionSourceSet = false;
|
||||
bool isConversionTargetSet = false;
|
||||
foreach (UCM.Unit unit in m_currencyUnits)
|
||||
{
|
||||
unit.isConversionSource = false;
|
||||
unit.isConversionTarget = false;
|
||||
|
||||
if (!isConversionSourceSet && unit.abbreviation == DEFAULT_FROM_CURRENCY)
|
||||
{
|
||||
unit.isConversionSource = true;
|
||||
isConversionSourceSet = true;
|
||||
}
|
||||
|
||||
if (!isConversionTargetSet && unit.abbreviation == DEFAULT_TO_CURRENCY)
|
||||
{
|
||||
unit.isConversionTarget = true;
|
||||
isConversionTargetSet = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NotifyDataLoadFinished(bool didLoad)
|
||||
{
|
||||
if (!didLoad)
|
||||
{
|
||||
m_loadStatus = CurrencyLoadStatus.FailedToLoad;
|
||||
}
|
||||
|
||||
if (m_vmCallback != null)
|
||||
{
|
||||
m_vmCallback.CurrencyDataLoadFinished(didLoad);
|
||||
}
|
||||
}
|
||||
|
||||
void SaveLangCodeAndTimestamp()
|
||||
{
|
||||
ApplicationDataContainer localSettings = ApplicationData.Current.LocalSettings;
|
||||
if (localSettings == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
localSettings.Values[CurrencyDataLoaderConstants.CacheTimestampKey] = m_cacheTimestamp.ToString("R");
|
||||
localSettings.Values[CurrencyDataLoaderConstants.CacheLangcodeKey] = m_responseLanguage;
|
||||
}
|
||||
|
||||
void UpdateDisplayedTimestamp()
|
||||
{
|
||||
if (m_vmCallback != null)
|
||||
{
|
||||
string timestamp = GetCurrencyTimestamp();
|
||||
bool isWeekOld = Utils.IsDateTimeOlderThan(m_cacheTimestamp, WEEK_DURATION);
|
||||
|
||||
m_vmCallback.CurrencyTimestampCallback(timestamp, isWeekOld);
|
||||
}
|
||||
}
|
||||
|
||||
public string GetCurrencyTimestamp()
|
||||
{
|
||||
string timestamp = "";
|
||||
|
||||
DateTime epoch = default(DateTime);
|
||||
if (m_cacheTimestamp.ToUniversalTime() != epoch.ToUniversalTime())
|
||||
{
|
||||
DateTimeFormatter dateFormatter = new DateTimeFormatter("{month.abbreviated} {day.integer}, {year.full}");
|
||||
string date = dateFormatter.Format(m_cacheTimestamp);
|
||||
|
||||
DateTimeFormatter timeFormatter = new DateTimeFormatter("shorttime");
|
||||
string time = timeFormatter.Format(m_cacheTimestamp);
|
||||
|
||||
timestamp = LocalizationStringUtil.GetLocalizedString(m_timestampFormat, date, time);
|
||||
}
|
||||
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
async Task<SelectedUnits> GetDefaultFromToCurrency()
|
||||
{
|
||||
string fromCurrency = DEFAULT_FROM_CURRENCY;
|
||||
string toCurrency = DEFAULT_TO_CURRENCY;
|
||||
|
||||
// First, check if we previously stored the last used currencies.
|
||||
bool foundInLocalSettings = TryGetLastUsedCurrenciesFromLocalSettings(out fromCurrency, out toCurrency);
|
||||
if (!foundInLocalSettings)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Second, see if the current locale has preset defaults in DefaultFromToCurrency.json.
|
||||
Uri fileUri = new Uri(DEFAULT_FROM_TO_CURRENCY_FILE_URI);
|
||||
StorageFile defaultFromToCurrencyFile = await StorageFile.GetFileFromApplicationUriAsync(fileUri); // TODO UNO
|
||||
if (defaultFromToCurrencyFile != null)
|
||||
{
|
||||
String fileContents = 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(FROM_KEY);
|
||||
String selectedTo = regionalDefaults.GetNamedString(TO_KEY);
|
||||
|
||||
fromCurrency = selectedFrom;
|
||||
toCurrency = selectedTo;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
return new SelectedUnits(fromCurrency, toCurrency);
|
||||
}
|
||||
|
||||
bool TryGetLastUsedCurrenciesFromLocalSettings(out string fromCurrency, out string toCurrency)
|
||||
{
|
||||
fromCurrency = toCurrency = null;
|
||||
|
||||
String fromKey = UnitConverterResourceKeys.CurrencyUnitFromKey;
|
||||
String toKey = UnitConverterResourceKeys.CurrencyUnitToKey;
|
||||
ApplicationDataContainer localSettings = ApplicationData.Current.LocalSettings;
|
||||
if (localSettings != null && localSettings.Values != null)
|
||||
{
|
||||
IPropertySet values = localSettings.Values;
|
||||
if (values.ContainsKey(fromKey) && values.ContainsKey(toKey))
|
||||
{
|
||||
fromCurrency = (String)(values[fromKey]);
|
||||
toCurrency = (String)(values[toKey]);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void SaveSelectedUnitsToLocalSettings(SelectedUnits selectedUnits)
|
||||
{
|
||||
String fromKey = UnitConverterResourceKeys.CurrencyUnitFromKey;
|
||||
String toKey = UnitConverterResourceKeys.CurrencyUnitToKey;
|
||||
ApplicationDataContainer localSettings = ApplicationData.Current.LocalSettings;
|
||||
if (localSettings != null && localSettings.Values != null)
|
||||
{
|
||||
IPropertySet values = localSettings.Values;
|
||||
values[fromKey] = selectedUnits.Key;
|
||||
values[toKey] = selectedUnits.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
53
src/Calculator.Shared/DataLoaders/CurrencyHttpClient.cs
Normal file
53
src/Calculator.Shared/DataLoaders/CurrencyHttpClient.cs
Normal file
|
@ -0,0 +1,53 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Windows.Foundation;
|
||||
using Windows.Web.Http;
|
||||
|
||||
namespace CalculatorApp.DataLoaders
|
||||
{
|
||||
public class CurrencyHttpClient : ICurrencyHttpClient
|
||||
{
|
||||
Windows.Web.Http.HttpClient m_client;
|
||||
string m_responseLanguage;
|
||||
string m_sourceCurrencyCode;
|
||||
|
||||
static string sc_MetadataUriLocalizeFor = "https://go.microsoft.com/fwlink/?linkid=2041093&localizeFor=";
|
||||
static string sc_RatiosUriRelativeTo = "https://go.microsoft.com/fwlink/?linkid=2041339&localCurrency=";
|
||||
|
||||
public CurrencyHttpClient()
|
||||
{
|
||||
m_client = new HttpClient();
|
||||
m_responseLanguage = "en-US";
|
||||
}
|
||||
|
||||
public void SetSourceCurrencyCode(String sourceCurrencyCode)
|
||||
{
|
||||
m_sourceCurrencyCode = sourceCurrencyCode;
|
||||
}
|
||||
|
||||
public void SetResponseLanguage(String responseLanguage)
|
||||
{
|
||||
m_responseLanguage = responseLanguage;
|
||||
}
|
||||
|
||||
public IAsyncOperationWithProgress<String, HttpProgress> GetCurrencyMetadata()
|
||||
{
|
||||
string uri = sc_MetadataUriLocalizeFor + m_responseLanguage;
|
||||
var metadataUri = new Uri(uri);
|
||||
|
||||
return m_client.GetStringAsync(metadataUri);
|
||||
}
|
||||
|
||||
public IAsyncOperationWithProgress<String, HttpProgress> GetCurrencyRatios()
|
||||
{
|
||||
string uri = sc_RatiosUriRelativeTo + m_sourceCurrencyCode;
|
||||
var ratiosUri = new Uri(uri);
|
||||
|
||||
return m_client.GetStringAsync(ratiosUri);
|
||||
}
|
||||
}
|
||||
}
|
18
src/Calculator.Shared/DataLoaders/ICurrencyHttpClient.cs
Normal file
18
src/Calculator.Shared/DataLoaders/ICurrencyHttpClient.cs
Normal file
|
@ -0,0 +1,18 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace CalculatorApp.DataLoaders
|
||||
{
|
||||
public interface ICurrencyHttpClient
|
||||
{
|
||||
void SetSourceCurrencyCode(string sourceCurrencyCode);
|
||||
void SetResponseLanguage(string responseLanguage);
|
||||
|
||||
Windows.Foundation.IAsyncOperationWithProgress<string, Windows.Web.Http.HttpProgress> GetCurrencyMetadata();
|
||||
Windows.Foundation.IAsyncOperationWithProgress<string, Windows.Web.Http.HttpProgress> GetCurrencyRatios();
|
||||
}
|
||||
}
|
170
src/Calculator.Shared/DataLoaders/UnitConverterDataConstants.cs
Normal file
170
src/Calculator.Shared/DataLoaders/UnitConverterDataConstants.cs
Normal file
|
@ -0,0 +1,170 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace CalculatorApp.ViewModel
|
||||
{
|
||||
public enum UnitConverterUnits
|
||||
{
|
||||
UnitStart = 0,
|
||||
Area_Acre = UnitStart + 1,
|
||||
Area_Hectare = UnitStart + 2,
|
||||
Area_SquareCentimeter = UnitStart + 3,
|
||||
Area_SquareFoot = UnitStart + 4,
|
||||
Area_SquareInch = UnitStart + 5,
|
||||
Area_SquareKilometer = UnitStart + 6,
|
||||
Area_SquareMeter = UnitStart + 7,
|
||||
Area_SquareMile = UnitStart + 8,
|
||||
Area_SquareMillimeter = UnitStart + 9,
|
||||
Area_SquareYard = UnitStart + 10,
|
||||
Data_Bit = UnitStart + 11,
|
||||
Data_Byte = UnitStart + 12,
|
||||
Data_Gigabit = UnitStart + 13,
|
||||
Data_Gigabyte = UnitStart + 14,
|
||||
Data_Kilobit = UnitStart + 15,
|
||||
Data_Kilobyte = UnitStart + 16,
|
||||
Data_Megabit = UnitStart + 17,
|
||||
Data_Megabyte = UnitStart + 18,
|
||||
Data_Petabit = UnitStart + 19,
|
||||
Data_Petabyte = UnitStart + 20,
|
||||
Data_Terabit = UnitStart + 21,
|
||||
Data_Terabyte = UnitStart + 22,
|
||||
Energy_BritishThermalUnit = UnitStart + 23,
|
||||
Energy_Calorie = UnitStart + 24,
|
||||
Energy_ElectronVolt = UnitStart + 25,
|
||||
Energy_FootPound = UnitStart + 26,
|
||||
Energy_Joule = UnitStart + 27,
|
||||
Energy_Kilocalorie = UnitStart + 28,
|
||||
Energy_Kilojoule = UnitStart + 29,
|
||||
Length_Centimeter = UnitStart + 30,
|
||||
Length_Foot = UnitStart + 31,
|
||||
Length_Inch = UnitStart + 32,
|
||||
Length_Kilometer = UnitStart + 33,
|
||||
Length_Meter = UnitStart + 34,
|
||||
Length_Micron = UnitStart + 35,
|
||||
Length_Mile = UnitStart + 36,
|
||||
Length_Millimeter = UnitStart + 37,
|
||||
Length_Nanometer = UnitStart + 38,
|
||||
Length_NauticalMile = UnitStart + 39,
|
||||
Length_Yard = UnitStart + 40,
|
||||
Power_BritishThermalUnitPerMinute = UnitStart + 41,
|
||||
Power_FootPoundPerMinute = UnitStart + 42,
|
||||
Power_Horsepower = UnitStart + 43,
|
||||
Power_Kilowatt = UnitStart + 44,
|
||||
Power_Watt = UnitStart + 45,
|
||||
Temperature_DegreesCelsius = UnitStart + 46,
|
||||
Temperature_DegreesFahrenheit = UnitStart + 47,
|
||||
Temperature_Kelvin = UnitStart + 48,
|
||||
Time_Day = UnitStart + 49,
|
||||
Time_Hour = UnitStart + 50,
|
||||
Time_Microsecond = UnitStart + 51,
|
||||
Time_Millisecond = UnitStart + 52,
|
||||
Time_Minute = UnitStart + 53,
|
||||
Time_Second = UnitStart + 54,
|
||||
Time_Week = UnitStart + 55,
|
||||
Time_Year = UnitStart + 56,
|
||||
Speed_CentimetersPerSecond = UnitStart + 57,
|
||||
Speed_FeetPerSecond = UnitStart + 58,
|
||||
Speed_KilometersPerHour = UnitStart + 59,
|
||||
Speed_Knot = UnitStart + 60,
|
||||
Speed_Mach = UnitStart + 61,
|
||||
Speed_MetersPerSecond = UnitStart + 62,
|
||||
Speed_MilesPerHour = UnitStart + 63,
|
||||
Volume_CubicCentimeter = UnitStart + 64,
|
||||
Volume_CubicFoot = UnitStart + 65,
|
||||
Volume_CubicInch = UnitStart + 66,
|
||||
Volume_CubicMeter = UnitStart + 67,
|
||||
Volume_CubicYard = UnitStart + 68,
|
||||
Volume_CupUS = UnitStart + 69,
|
||||
Volume_FluidOunceUK = UnitStart + 70,
|
||||
Volume_FluidOunceUS = UnitStart + 71,
|
||||
Volume_GallonUK = UnitStart + 72,
|
||||
Volume_GallonUS = UnitStart + 73,
|
||||
Volume_Liter = UnitStart + 74,
|
||||
Volume_Milliliter = UnitStart + 75,
|
||||
Volume_PintUK = UnitStart + 76,
|
||||
Volume_PintUS = UnitStart + 77,
|
||||
Volume_TablespoonUS = UnitStart + 78,
|
||||
Volume_TeaspoonUS = UnitStart + 79,
|
||||
Volume_QuartUK = UnitStart + 80,
|
||||
Volume_QuartUS = UnitStart + 81,
|
||||
Weight_Carat = UnitStart + 82,
|
||||
Weight_Centigram = UnitStart + 83,
|
||||
Weight_Decigram = UnitStart + 84,
|
||||
Weight_Decagram = UnitStart + 85,
|
||||
Weight_Gram = UnitStart + 86,
|
||||
Weight_Hectogram = UnitStart + 87,
|
||||
Weight_Kilogram = UnitStart + 88,
|
||||
Weight_LongTon = UnitStart + 89,
|
||||
Weight_Milligram = UnitStart + 90,
|
||||
Weight_Ounce = UnitStart + 91,
|
||||
Weight_Pound = UnitStart + 92,
|
||||
Weight_ShortTon = UnitStart + 93,
|
||||
Weight_Stone = UnitStart + 94,
|
||||
Weight_Tonne = UnitStart + 95,
|
||||
Area_SoccerField = UnitStart + 99,
|
||||
Data_FloppyDisk = UnitStart + 100,
|
||||
Data_CD = UnitStart + 101,
|
||||
Data_DVD = UnitStart + 102,
|
||||
Energy_Battery = UnitStart + 103,
|
||||
Length_Paperclip = UnitStart + 105,
|
||||
Length_JumboJet = UnitStart + 107,
|
||||
Power_LightBulb = UnitStart + 108,
|
||||
Power_Horse = UnitStart + 109,
|
||||
Volume_Bathtub = UnitStart + 111,
|
||||
Weight_Snowflake = UnitStart + 113,
|
||||
Weight_Elephant = UnitStart + 114,
|
||||
Volume_TeaspoonUK = UnitStart + 115,
|
||||
Volume_TablespoonUK = UnitStart + 116,
|
||||
Area_Hand = UnitStart + 118,
|
||||
Speed_Turtle = UnitStart + 121,
|
||||
Speed_Jet = UnitStart + 122,
|
||||
Volume_CoffeeCup = UnitStart + 124,
|
||||
Weight_Whale = UnitStart + 123,
|
||||
Volume_SwimmingPool = UnitStart + 125,
|
||||
Speed_Horse = UnitStart + 126,
|
||||
Area_Paper = UnitStart + 127,
|
||||
Area_Castle = UnitStart + 128,
|
||||
Energy_Banana = UnitStart + 129,
|
||||
Energy_SliceOfCake = UnitStart + 130,
|
||||
Length_Hand = UnitStart + 131,
|
||||
Power_TrainEngine = UnitStart + 132,
|
||||
Weight_SoccerBall = UnitStart + 133,
|
||||
Angle_Degree = UnitStart + 134,
|
||||
Angle_Radian = UnitStart + 135,
|
||||
Angle_Gradian = UnitStart + 136,
|
||||
Pressure_Atmosphere = UnitStart + 137,
|
||||
Pressure_Bar = UnitStart + 138,
|
||||
Pressure_KiloPascal = UnitStart + 139,
|
||||
Pressure_MillimeterOfMercury = UnitStart + 140,
|
||||
Pressure_Pascal = UnitStart + 141,
|
||||
Pressure_PSI = UnitStart + 142,
|
||||
Data_Exabits = UnitStart + 143,
|
||||
Data_Exabytes = UnitStart + 144,
|
||||
Data_Exbibits = UnitStart + 145,
|
||||
Data_Exbibytes = UnitStart + 146,
|
||||
Data_Gibibits = UnitStart + 147,
|
||||
Data_Gibibytes = UnitStart + 148,
|
||||
Data_Kibibits = UnitStart + 149,
|
||||
Data_Kibibytes = UnitStart + 150,
|
||||
Data_Mebibits = UnitStart + 151,
|
||||
Data_Mebibytes = UnitStart + 152,
|
||||
Data_Pebibits = UnitStart + 153,
|
||||
Data_Pebibytes = UnitStart + 154,
|
||||
Data_Tebibits = UnitStart + 155,
|
||||
Data_Tebibytes = UnitStart + 156,
|
||||
Data_Yobibits = UnitStart + 157,
|
||||
Data_Yobibytes = UnitStart + 158,
|
||||
Data_Yottabit = UnitStart + 159,
|
||||
Data_Yottabyte = UnitStart + 160,
|
||||
Data_Zebibits = UnitStart + 161,
|
||||
Data_Zebibytes = UnitStart + 162,
|
||||
Data_Zetabits = UnitStart + 163,
|
||||
Data_Zetabytes = UnitStart + 164,
|
||||
Area_Pyeong = UnitStart + 165,
|
||||
UnitEnd = Area_Pyeong
|
||||
};
|
||||
}
|
1322
src/Calculator.Shared/DataLoaders/UnitConverterDataLoader.cs
Normal file
1322
src/Calculator.Shared/DataLoaders/UnitConverterDataLoader.cs
Normal file
File diff suppressed because it is too large
Load diff
|
@ -21,6 +21,7 @@ using System.Windows.Input;
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Collections.ObjectModel;
|
||||
using CalculatorApp.DataLoaders;
|
||||
|
||||
namespace CalculatorApp.ViewModel
|
||||
{
|
||||
|
@ -38,10 +39,8 @@ namespace CalculatorApp.ViewModel
|
|||
private DateCalculatorViewModel m_DateCalcViewModel;
|
||||
public DateCalculatorViewModel DateCalcViewModel { get => m_DateCalcViewModel; set { m_DateCalcViewModel = value; RaisePropertyChanged("DateCalcViewModel"); } }
|
||||
|
||||
|
||||
// UNO TODO
|
||||
//private UnitConverterViewModel m_ConverterViewModel;
|
||||
//public UnitConverterViewModel ConverterViewModel { get => m_ConverterViewModel; set { m_ConverterViewModel = value; RaisePropertyChanged("ConverterViewModel"); } }
|
||||
private UnitConverterViewModel m_ConverterViewModel;
|
||||
public UnitConverterViewModel ConverterViewModel { get => m_ConverterViewModel; set { m_ConverterViewModel = value; RaisePropertyChanged("ConverterViewModel"); } }
|
||||
|
||||
|
||||
private CalculatorApp.Common.ViewMode m_PreviousMode;
|
||||
|
@ -62,7 +61,7 @@ namespace CalculatorApp.ViewModel
|
|||
|
||||
|
||||
ViewMode m_mode = ViewMode.None;
|
||||
ObservableCollection<NavCategoryGroup> m_categories;
|
||||
CalculatorObservableCollection<NavCategoryGroup> m_categories;
|
||||
|
||||
public ApplicationViewModel()
|
||||
{
|
||||
|
@ -87,7 +86,7 @@ namespace CalculatorApp.ViewModel
|
|||
}
|
||||
}
|
||||
|
||||
public ObservableCollection<NavCategoryGroup> Categories
|
||||
public CalculatorObservableCollection<NavCategoryGroup> Categories
|
||||
{
|
||||
get => m_categories;
|
||||
set
|
||||
|
@ -166,17 +165,16 @@ namespace CalculatorApp.ViewModel
|
|||
}
|
||||
else if (NavCategory.IsConverterViewMode(m_mode))
|
||||
{
|
||||
// UNO TODO
|
||||
//// TraceLogger.GetInstance().LogConverterModeViewed(m_mode, ApplicationView.GetApplicationViewIdForWindow(CoreWindow.GetForCurrentThread()));
|
||||
//if (!m_ConverterViewModel)
|
||||
//{
|
||||
// var dataLoader = new UnitConverterDataLoader(new GeographicRegion());
|
||||
// var currencyDataLoader = new CurrencyDataLoader(new CurrencyHttpClient());
|
||||
// m_ConverterViewModel = new UnitConverterViewModel(new UnitConversionManager.UnitConverter(dataLoader, currencyDataLoader));
|
||||
//}
|
||||
// TraceLogger.GetInstance().LogConverterModeViewed(m_mode, ApplicationView.GetApplicationViewIdForWindow(CoreWindow.GetForCurrentThread()));
|
||||
if (m_ConverterViewModel == null)
|
||||
{
|
||||
var dataLoader = new UnitConverterDataLoader(new GeographicRegion());
|
||||
var currencyDataLoader = new CurrencyDataLoader(new CurrencyHttpClient());
|
||||
m_ConverterViewModel = new UnitConverterViewModel(new UnitConversionManager.UnitConverter(dataLoader, currencyDataLoader));
|
||||
}
|
||||
|
||||
//m_ConverterViewModel.Mode = m_mode;
|
||||
}
|
||||
m_ConverterViewModel.Mode = m_mode;
|
||||
}
|
||||
|
||||
var resProvider = AppResourceProvider.GetInstance();
|
||||
CategoryName = resProvider.GetResourceString(NavCategory.GetNameResourceKey(m_mode));
|
||||
|
@ -193,13 +191,11 @@ namespace CalculatorApp.ViewModel
|
|||
|
||||
void OnCopyCommand(object parameter)
|
||||
{
|
||||
// UNO TODO
|
||||
//if (NavCategory.IsConverterViewMode(m_mode))
|
||||
//{
|
||||
// ConverterViewModel.OnCopyCommand(parameter);
|
||||
//}
|
||||
//else
|
||||
if (NavCategory.IsDateCalculatorViewMode(m_mode))
|
||||
if (NavCategory.IsConverterViewMode(m_mode))
|
||||
{
|
||||
ConverterViewModel.OnCopyCommand(parameter);
|
||||
}
|
||||
else if (NavCategory.IsDateCalculatorViewMode(m_mode))
|
||||
{
|
||||
DateCalcViewModel.OnCopyCommand(parameter);
|
||||
}
|
||||
|
@ -211,13 +207,11 @@ namespace CalculatorApp.ViewModel
|
|||
|
||||
void OnPasteCommand(object parameter)
|
||||
{
|
||||
// UNO TODO
|
||||
//if (NavCategory.IsConverterViewMode(m_mode))
|
||||
//{
|
||||
// ConverterViewModel.OnPasteCommand(parameter);
|
||||
//}
|
||||
//else
|
||||
if (NavCategory.IsCalculatorViewMode(m_mode))
|
||||
if (NavCategory.IsConverterViewMode(m_mode))
|
||||
{
|
||||
ConverterViewModel.OnPasteCommand(parameter);
|
||||
}
|
||||
else if (NavCategory.IsCalculatorViewMode(m_mode))
|
||||
{
|
||||
CalculatorViewModel.OnPasteCommand(parameter);
|
||||
}
|
||||
|
|
|
@ -30,8 +30,8 @@ namespace CalculatorApp
|
|||
public int ItemSize { get => m_ItemSize; set { m_ItemSize = value; RaisePropertyChanged("ItemSize"); } }
|
||||
|
||||
|
||||
private ObservableCollection<HistoryItemViewModel> m_Items;
|
||||
public ObservableCollection<HistoryItemViewModel> Items { get => m_Items; set { m_Items = value; RaisePropertyChanged("Items"); } }
|
||||
private CalculatorObservableCollection<HistoryItemViewModel> m_Items;
|
||||
public CalculatorObservableCollection<HistoryItemViewModel> Items { get => m_Items; set { m_Items = value; RaisePropertyChanged("Items"); } }
|
||||
|
||||
|
||||
private bool m_AreHistoryShortcutsEnabled;
|
||||
|
@ -70,7 +70,7 @@ namespace CalculatorApp
|
|||
|
||||
AreHistoryShortcutsEnabled = true;
|
||||
|
||||
Items = new ObservableCollection<HistoryItemViewModel>();
|
||||
Items = new CalculatorObservableCollection<HistoryItemViewModel>();
|
||||
ItemSize = 0;
|
||||
}
|
||||
|
||||
|
@ -97,7 +97,7 @@ namespace CalculatorApp
|
|||
}
|
||||
|
||||
var historyListModel = m_calculatorManager.GetHistoryItems(m_currentMode);
|
||||
var historyListVM = new ObservableCollection<HistoryItemViewModel>();
|
||||
var historyListVM = new CalculatorObservableCollection<HistoryItemViewModel>();
|
||||
var localizer = LocalizationSettings.GetInstance();
|
||||
if (historyListModel.Count > 0)
|
||||
{
|
||||
|
|
|
@ -23,6 +23,7 @@ using System.Text;
|
|||
using System.Linq;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Threading.Tasks;
|
||||
using Calculator;
|
||||
|
||||
namespace CalculatorApp.ViewModel
|
||||
{
|
||||
|
@ -86,8 +87,8 @@ namespace CalculatorApp.ViewModel
|
|||
public string DisplayStringExpression { get => m_DisplayStringExpression; set { m_DisplayStringExpression = value; RaisePropertyChanged("DisplayStringExpression"); } }
|
||||
|
||||
|
||||
private ObservableCollection<Common.DisplayExpressionToken> m_ExpressionTokens;
|
||||
public ObservableCollection<Common.DisplayExpressionToken> ExpressionTokens { get => m_ExpressionTokens; private set { m_ExpressionTokens = value; RaisePropertyChanged("ExpressionTokens"); } }
|
||||
private CalculatorObservableCollection<Common.DisplayExpressionToken> m_ExpressionTokens;
|
||||
public CalculatorObservableCollection<Common.DisplayExpressionToken> ExpressionTokens { get => m_ExpressionTokens; private set { m_ExpressionTokens = value; RaisePropertyChanged("ExpressionTokens"); } }
|
||||
|
||||
|
||||
private string m_DecimalDisplayValue;
|
||||
|
@ -518,7 +519,7 @@ namespace CalculatorApp.ViewModel
|
|||
m_BinaryDisplayValue = "0";
|
||||
m_OctalDisplayValue = "0";
|
||||
m_standardCalculatorManager = new CalculatorManager(ref m_calculatorDisplay, ref m_resourceProvider);
|
||||
m_ExpressionTokens = new ObservableCollection<DisplayExpressionToken>();
|
||||
m_ExpressionTokens = new CalculatorObservableCollection<DisplayExpressionToken>();
|
||||
m_MemorizedNumbers = new List<MemoryItemViewModel>();
|
||||
m_IsMemoryEmpty = true;
|
||||
m_IsFToEChecked = false;
|
||||
|
@ -618,7 +619,7 @@ namespace CalculatorApp.ViewModel
|
|||
if (Utils.IsLastCharacterTarget(displayValue, m_decimalSeparator))
|
||||
{
|
||||
// remove the decimal separator, to avoid a long pause between words
|
||||
localizedValue = LocalizeDisplayValue(displayValue.Substring(0, displayValue.Length - 1), isError);
|
||||
localizedValue = LocalizeDisplayValue(displayValue.substr(0, displayValue.Length - 1), isError);
|
||||
|
||||
// Use a format which has a word in the decimal separator's place
|
||||
// "The Display is 10 point"
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -25,14 +25,14 @@
|
|||
-->
|
||||
|
||||
<!-- CalculatorBaseStyle -->
|
||||
<Style x:Name="CalculatorBaseStyle"
|
||||
<Style x:Key="CalculatorBaseStyle"
|
||||
TargetType="local:Calculator">
|
||||
<Setter Property="Margin"
|
||||
Value="0,0,0,0"/>
|
||||
</Style>
|
||||
|
||||
<!-- UnitConverterBaseStyle -->
|
||||
<Style x:Name="UnitConverterBaseStyle"
|
||||
<Style x:Key="UnitConverterBaseStyle"
|
||||
TargetType="local:UnitConverter">
|
||||
<Setter Property="Visibility"
|
||||
Value="Collapsed"/>
|
||||
|
|
|
@ -225,8 +225,7 @@ namespace CalculatorApp
|
|||
if (NavCategory.IsConverterViewMode(m_model.Mode))
|
||||
{
|
||||
int modeIndex = NavCategory.GetIndexInGroup(m_model.Mode, CategoryGroupType.Converter);
|
||||
// UNO TODO
|
||||
// m_model.ConverterViewModel.CurrentCategory = m_model.ConverterViewModel.Categories.GetAt(modeIndex);
|
||||
m_model.ConverterViewModel.CurrentCategory = m_model.ConverterViewModel.Categories.GetAt(modeIndex);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -288,11 +287,10 @@ namespace CalculatorApp
|
|||
{
|
||||
m_dateCalculator.SetDefaultFocus();
|
||||
}
|
||||
// UNO TODO
|
||||
//if (m_converter != null && m_converter.Visibility == Visibility.Visible)
|
||||
//{
|
||||
// m_converter.SetDefaultFocus();
|
||||
//}
|
||||
if (m_converter != null && m_converter.Visibility == Visibility.Visible)
|
||||
{
|
||||
m_converter.SetDefaultFocus();
|
||||
}
|
||||
}
|
||||
|
||||
void EnsureCalculator()
|
||||
|
@ -312,11 +310,7 @@ namespace CalculatorApp
|
|||
Binding isProgramerBinding = new Binding();
|
||||
isProgramerBinding.Path = new PropertyPath("IsProgrammer");
|
||||
m_calculator.SetBinding(CalculatorApp.Calculator.IsProgrammerProperty, isProgramerBinding);
|
||||
|
||||
#if NETFX_CORE
|
||||
// UNO TODO
|
||||
m_calculator.Style = CalculatorBaseStyle;
|
||||
#endif
|
||||
m_calculator.Style = (Style)Resources["CalculatorBaseStyle"];
|
||||
|
||||
CalcHolder.Child = m_calculator;
|
||||
|
||||
|
@ -354,17 +348,16 @@ namespace CalculatorApp
|
|||
|
||||
void EnsureConverter()
|
||||
{
|
||||
// UNO TODO
|
||||
//if (m_converter == null)
|
||||
//{
|
||||
// // delay loading converter
|
||||
// m_converter = new CalculatorApp.UnitConverter();
|
||||
// m_converter.Name = "unitConverter";
|
||||
// m_converter.DataContext = m_model.ConverterViewModel;
|
||||
// m_converter.Style = UnitConverterBaseStyle;
|
||||
// ConverterHolder.Child = m_converter;
|
||||
//}
|
||||
}
|
||||
if (m_converter == null)
|
||||
{
|
||||
// delay loading converter
|
||||
m_converter = new CalculatorApp.UnitConverter();
|
||||
m_converter.Name = "unitConverter";
|
||||
m_converter.DataContext = m_model.ConverterViewModel;
|
||||
m_converter.Style = (Style)Resources["UnitConverterBaseStyle"];
|
||||
ConverterHolder.Child = m_converter;
|
||||
}
|
||||
}
|
||||
|
||||
void OnNavLoaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
|
@ -449,7 +442,7 @@ namespace CalculatorApp
|
|||
|
||||
public CalculatorList<object> UIElementsForCategories => CreateUIElementsForCategories(Model.Categories);
|
||||
|
||||
public CalculatorList<object> CreateUIElementsForCategories(ObservableCollection<NavCategoryGroup> categories)
|
||||
public CalculatorList<object> CreateUIElementsForCategories(CalculatorObservableCollection<NavCategoryGroup> categories)
|
||||
{
|
||||
var menuCategories = new CalculatorList<object>();
|
||||
|
||||
|
@ -552,14 +545,12 @@ namespace CalculatorApp
|
|||
{
|
||||
String categoryName = AutomationProperties.GetName(Header);
|
||||
NarratorAnnouncement announcement = CalculatorAnnouncement.GetCategoryNameChangedAnnouncement(categoryName);
|
||||
// UNO TODO
|
||||
// NarratorNotifier.Announce(announcement);
|
||||
//NarratorNotifier.Announce(announcement);
|
||||
}
|
||||
|
||||
void OnNavItemInvoked(NavigationView sender, NavigationViewItemInvokedEventArgs e)
|
||||
{
|
||||
NavView.IsPaneOpen = false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -90,10 +90,10 @@ namespace CalculatorApp.Views.StateTriggers
|
|||
);
|
||||
|
||||
|
||||
AspectRatioTrigger()
|
||||
{
|
||||
SetActive(false);
|
||||
}
|
||||
public AspectRatioTrigger()
|
||||
{
|
||||
SetActive(false);
|
||||
}
|
||||
|
||||
void OnSourcePropertyChanged(FrameworkElement oldValue, FrameworkElement newValue)
|
||||
{
|
||||
|
|
|
@ -3,87 +3,84 @@
|
|||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:common="using:CalculatorApp.Common"
|
||||
xmlns:controls="using:CalculatorApp.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:designdata="using:CalculatorApp.DesignData"
|
||||
xmlns:local="using:CalculatorApp.Views"
|
||||
xmlns:local="using:CalculatorApp"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:vm="using:CalculatorApp.ViewModel"
|
||||
mc:Ignorable="">
|
||||
d:DesignHeight="300"
|
||||
d:DesignWidth="400"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<!--<UserControl.Resources>
|
||||
<DataTemplate x:Name="SupplementaryValueTemplate"
|
||||
x:DataType="vm:SupplementaryResult">
|
||||
<StackPanel Margin="0"
|
||||
Orientation="Horizontal">
|
||||
<UserControl.Resources>
|
||||
<DataTemplate x:Key="SupplementaryValueTemplate" x:DataType="vm:SupplementaryResult">
|
||||
<StackPanel Margin="0" Orientation="Horizontal">
|
||||
<TextBlock Margin="0,0,4,0"
|
||||
Padding="0"
|
||||
VerticalAlignment="Bottom"
|
||||
Style="{ThemeResource BaseTextBlockStyle}"
|
||||
Foreground="{ThemeResource SystemControlPageTextBaseHighBrush}"
|
||||
AutomationProperties.AutomationId="SupplementaryResultValue"
|
||||
IsTextScaleFactorEnabled="False"
|
||||
Text="{x:Bind Value}" />
|
||||
Padding="0"
|
||||
VerticalAlignment="Bottom"
|
||||
Style="{ThemeResource BaseTextBlockStyle}"
|
||||
Foreground="{ThemeResource SystemControlPageTextBaseHighBrush}"
|
||||
AutomationProperties.AutomationId="SupplementaryResultValue"
|
||||
IsTextScaleFactorEnabled="False"
|
||||
Text="{x:Bind Value}"/>
|
||||
<TextBlock Margin="0,0,16,0"
|
||||
Padding="0"
|
||||
VerticalAlignment="Bottom"
|
||||
Style="{ThemeResource BodyTextBlockStyle}"
|
||||
Foreground="{ThemeResource SystemControlPageTextBaseMediumBrush}"
|
||||
AutomationProperties.AutomationId="SupplementaryResultUnit"
|
||||
IsTextScaleFactorEnabled="False"
|
||||
Text="{x:Bind Unit.Abbreviation}" />
|
||||
Padding="0"
|
||||
VerticalAlignment="Bottom"
|
||||
Style="{ThemeResource BodyTextBlockStyle}"
|
||||
Foreground="{ThemeResource SystemControlPageTextBaseMediumBrush}"
|
||||
AutomationProperties.AutomationId="SupplementaryResultUnit"
|
||||
IsTextScaleFactorEnabled="False"
|
||||
Text="{x:Bind Unit.Abbreviation}"/>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
|
||||
<local:DelighterUnitToStyleConverter x:Key="DelighterUnitStyleConverter" />
|
||||
<DataTemplate x:Name="DelighterValueTemplate"
|
||||
x:DataType="vm:SupplementaryResult">
|
||||
<StackPanel Margin="0"
|
||||
Orientation="Horizontal">
|
||||
<local:DelighterUnitToStyleConverter x:Key="DelighterUnitStyleConverter"/>
|
||||
<DataTemplate x:Key="DelighterValueTemplate" x:DataType="vm:SupplementaryResult">
|
||||
<StackPanel Margin="0" Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Bottom"
|
||||
Style="{Binding Unit, Converter={StaticResource DelighterUnitStyleConverter}, Mode=OneTime}"
|
||||
AutomationProperties.AutomationId="DelighterResultGlyph" />
|
||||
Style="{Binding Unit, Converter={StaticResource DelighterUnitStyleConverter}, Mode=OneTime}"
|
||||
AutomationProperties.AutomationId="DelighterResultGlyph"/>
|
||||
<TextBlock Margin="-2,0,4,0"
|
||||
Padding="0"
|
||||
VerticalAlignment="Bottom"
|
||||
Style="{ThemeResource BaseTextBlockStyle}"
|
||||
Foreground="{ThemeResource SystemControlPageTextBaseHighBrush}"
|
||||
AutomationProperties.AutomationId="DelighterResultValue"
|
||||
IsTextScaleFactorEnabled="False"
|
||||
Text="{x:Bind Value}" />
|
||||
Padding="0"
|
||||
VerticalAlignment="Bottom"
|
||||
Style="{ThemeResource BaseTextBlockStyle}"
|
||||
Foreground="{ThemeResource SystemControlPageTextBaseHighBrush}"
|
||||
AutomationProperties.AutomationId="DelighterResultValue"
|
||||
IsTextScaleFactorEnabled="False"
|
||||
Text="{x:Bind Value}"/>
|
||||
<TextBlock Margin="0"
|
||||
Padding="0"
|
||||
VerticalAlignment="Bottom"
|
||||
Style="{ThemeResource BodyTextBlockStyle}"
|
||||
Foreground="{ThemeResource SystemControlPageTextBaseMediumBrush}"
|
||||
AutomationProperties.AutomationId="DelighterResultUnit"
|
||||
IsTextScaleFactorEnabled="False"
|
||||
Text="{x:Bind Unit.Abbreviation}" />
|
||||
Padding="0"
|
||||
VerticalAlignment="Bottom"
|
||||
Style="{ThemeResource BodyTextBlockStyle}"
|
||||
Foreground="{ThemeResource SystemControlPageTextBaseMediumBrush}"
|
||||
AutomationProperties.AutomationId="DelighterResultUnit"
|
||||
IsTextScaleFactorEnabled="False"
|
||||
Text="{x:Bind Unit.Abbreviation}"/>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
|
||||
<local:SupplementaryResultDataTemplateSelector x:Key="ResultTemplateSelector"
|
||||
DelighterTemplate="{StaticResource DelighterValueTemplate}"
|
||||
RegularTemplate="{StaticResource SupplementaryValueTemplate}" />
|
||||
DelighterTemplate="{StaticResource DelighterValueTemplate}"
|
||||
RegularTemplate="{StaticResource SupplementaryValueTemplate}"/>
|
||||
|
||||
<Style x:Key="SupplementaryValuesStyle"
|
||||
TargetType="controls:SupplementaryItemsControl">
|
||||
<Setter Property="IsTabStop"
|
||||
Value="False" />
|
||||
<Style x:Key="SupplementaryValuesStyle" TargetType="controls:SupplementaryItemsControl">
|
||||
<Setter Property="IsTabStop" Value="False"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="controls:SupplementaryItemsControl">
|
||||
<ItemsPresenter />
|
||||
<ItemsPresenter/>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Setter Property="ItemContainerTransitions">
|
||||
<Setter.Value>
|
||||
<TransitionCollection />
|
||||
<TransitionCollection/>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Setter Property="ItemsPanel">
|
||||
<Setter.Value>
|
||||
<ItemsPanelTemplate>
|
||||
<StackPanel Orientation="Horizontal" />
|
||||
<local:SupplementaryResultNoOverflowStackPanel/>
|
||||
</ItemsPanelTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
|
@ -93,18 +90,18 @@
|
|||
|
||||
<StackPanel>
|
||||
<TextBlock x:Uid="SupplementaryResultsHeader"
|
||||
Margin="0,0,0,-6"
|
||||
HorizontalAlignment="Left"
|
||||
Style="{ThemeResource CaptionTextBlockStyle}"
|
||||
Foreground="{ThemeResource SystemControlPageTextBaseMediumBrush}"
|
||||
IsTextScaleFactorEnabled="False"
|
||||
Text="Also equal to" />
|
||||
Margin="0,0,0,-6"
|
||||
HorizontalAlignment="Left"
|
||||
Style="{ThemeResource CaptionTextBlockStyle}"
|
||||
Foreground="{ThemeResource SystemControlPageTextBaseMediumBrush}"
|
||||
IsTextScaleFactorEnabled="False"
|
||||
Text="Also equal to"/>
|
||||
<controls:SupplementaryItemsControl x:Name="SupplementaryValues"
|
||||
MinHeight="27"
|
||||
HorizontalAlignment="Left"
|
||||
Style="{ThemeResource SupplementaryValuesStyle}"
|
||||
IsTextScaleFactorEnabled="False"
|
||||
ItemTemplateSelector="{StaticResource ResultTemplateSelector}"
|
||||
LayoutUpdated="OnSupplementaryValuesLayoutUpdated" />
|
||||
</StackPanel>-->
|
||||
MinHeight="27"
|
||||
HorizontalAlignment="Left"
|
||||
Style="{ThemeResource SupplementaryValuesStyle}"
|
||||
IsTextScaleFactorEnabled="False"
|
||||
ItemTemplateSelector="{StaticResource ResultTemplateSelector}"
|
||||
ItemsSource="{x:Bind Results, Mode=OneWay}"/>
|
||||
</StackPanel>
|
||||
</UserControl>
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
using System;
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices.WindowsRuntime;
|
||||
|
@ -12,16 +17,116 @@ using Windows.UI.Xaml.Data;
|
|||
using Windows.UI.Xaml.Input;
|
||||
using Windows.UI.Xaml.Media;
|
||||
using Windows.UI.Xaml.Navigation;
|
||||
using CalculatorApp.Controls;
|
||||
using CalculatorApp.ViewModel;
|
||||
|
||||
// The User Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234236
|
||||
|
||||
namespace CalculatorApp
|
||||
{
|
||||
public sealed class DelighterUnitToStyleConverter : Windows.UI.Xaml.Data.IValueConverter
|
||||
{
|
||||
private Windows.UI.Xaml.ResourceDictionary m_delighters;
|
||||
|
||||
public DelighterUnitToStyleConverter()
|
||||
{
|
||||
m_delighters = new Windows.UI.Xaml.ResourceDictionary();
|
||||
m_delighters.Source = new Uri("ms-appx:///Views/DelighterUnitStyles.xaml");
|
||||
}
|
||||
|
||||
public object Convert(object value, Type targetType, object parameter, string language)
|
||||
{
|
||||
Unit unit = value as Unit;
|
||||
|
||||
Debug.Assert(unit.GetModelUnit().isWhimsical);
|
||||
if ((!unit?.GetModelUnit().isWhimsical) ?? true)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
string key = "Unit_" + unit.GetModelUnit().id;
|
||||
return m_delighters[key];
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, string language)
|
||||
{
|
||||
// We never use convert back, only one way binding supported
|
||||
Debug.Assert(false);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
public sealed class SupplementaryResultDataTemplateSelector : Windows.UI.Xaml.Controls.DataTemplateSelector
|
||||
{
|
||||
Windows.UI.Xaml.DataTemplate m_regularTemplate;
|
||||
Windows.UI.Xaml.DataTemplate m_delighterTemplate;
|
||||
|
||||
public Windows.UI.Xaml.DataTemplate RegularTemplate
|
||||
{
|
||||
get { return m_regularTemplate; }
|
||||
set { m_regularTemplate = value; }
|
||||
}
|
||||
|
||||
public Windows.UI.Xaml.DataTemplate DelighterTemplate
|
||||
{
|
||||
get { return m_delighterTemplate; }
|
||||
set { m_delighterTemplate = value; }
|
||||
}
|
||||
|
||||
protected override Windows.UI.Xaml.DataTemplate SelectTemplateCore(object item, DependencyObject container)
|
||||
{
|
||||
SupplementaryResult result = item as SupplementaryResult;
|
||||
if (result?.IsWhimsical() ?? false)
|
||||
{
|
||||
return DelighterTemplate;
|
||||
}
|
||||
else
|
||||
{
|
||||
return RegularTemplate;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed partial class SupplementaryResults : UserControl
|
||||
{
|
||||
// TODO UNO: DEPENDENCY_PROPERTY_OWNER(SupplementaryResults);
|
||||
// DEPENDENCY_PROPERTY_INITIALIZATION(SupplementaryResults, Results);
|
||||
|
||||
public static readonly DependencyProperty ResultProperty = DependencyProperty.Register(
|
||||
"Results",
|
||||
typeof(System.Collections.Generic.IEnumerable<ViewModel.SupplementaryResult>),
|
||||
typeof(SupplementaryResults),
|
||||
new PropertyMetadata(default(System.Collections.Generic.IEnumerable<ViewModel.SupplementaryResult>)));
|
||||
|
||||
public System.Collections.Generic.IEnumerable<ViewModel.SupplementaryResult> Results
|
||||
{
|
||||
get { return (System.Collections.Generic.IEnumerable<ViewModel.SupplementaryResult>)GetValue(ResultProperty); }
|
||||
set { SetValue(ResultProperty, value); }
|
||||
}
|
||||
|
||||
public SupplementaryResults()
|
||||
{
|
||||
Results = new CalculatorObservableCollection<SupplementaryResult>();
|
||||
|
||||
this.InitializeComponent();
|
||||
}
|
||||
}
|
||||
|
||||
public sealed partial class SupplementaryResultNoOverflowStackPanel : HorizontalNoOverflowStackPanel
|
||||
{
|
||||
protected override bool ShouldPrioritizeLastItem()
|
||||
{
|
||||
if (Children.Count == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
var lastChild = Children.Last() as FrameworkElement;
|
||||
if (lastChild == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
var suppResult = lastChild.DataContext as SupplementaryResult;
|
||||
return suppResult == null ? false : suppResult.IsWhimsical();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,17 +1,30 @@
|
|||
using System;
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices.WindowsRuntime;
|
||||
using Windows.Foundation;
|
||||
using Windows.Foundation.Collections;
|
||||
using Windows.System;
|
||||
using Windows.UI.ViewManagement;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Automation;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Controls.Primitives;
|
||||
using Windows.UI.Xaml.Data;
|
||||
using Windows.UI.Xaml.Input;
|
||||
using Windows.UI.Xaml.Media;
|
||||
using Windows.UI.Xaml.Navigation;
|
||||
using Calculator;
|
||||
using CalculatorApp.Common;
|
||||
using CalculatorApp.Controls;
|
||||
using CalculatorApp.ViewModel;
|
||||
using UnitConversionManager;
|
||||
|
||||
// The User Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234236
|
||||
|
||||
|
@ -19,9 +32,365 @@ namespace CalculatorApp
|
|||
{
|
||||
public sealed partial class UnitConverter : UserControl
|
||||
{
|
||||
const long DURATION_500_MS = 10000 * 500;
|
||||
|
||||
Windows.UI.Xaml.FlowDirection m_layoutDirection;
|
||||
//Windows.Foundation.EventRegistrationToken m_propertyChangedToken;
|
||||
Windows.UI.Xaml.Controls.MenuFlyout m_resultsFlyout;
|
||||
|
||||
string m_chargesMayApplyText;
|
||||
string m_failedToRefreshText;
|
||||
|
||||
bool m_meteredConnectionOverride;
|
||||
|
||||
Windows.UI.Xaml.DispatcherTimer m_delayTimer;
|
||||
|
||||
bool m_isAnimationEnabled;
|
||||
|
||||
// TODO UNO: DEPENDENCY_PROPERTY_OWNER(UnitConverter);
|
||||
|
||||
private HorizontalAlignment m_FlowDirectionHorizontalAlignment;
|
||||
public HorizontalAlignment FlowDirectionHorizontalAlignment
|
||||
{
|
||||
get => m_FlowDirectionHorizontalAlignment;
|
||||
set => m_FlowDirectionHorizontalAlignment = value;
|
||||
}
|
||||
|
||||
public UnitConverterViewModel Model
|
||||
{
|
||||
get { return (UnitConverterViewModel)this.DataContext; }
|
||||
}
|
||||
|
||||
public FlowDirection LayoutDirection
|
||||
|
||||
{
|
||||
get { return m_layoutDirection;
|
||||
}
|
||||
}
|
||||
|
||||
public UnitConverter()
|
||||
{
|
||||
m_meteredConnectionOverride = false;
|
||||
m_isAnimationEnabled = false;
|
||||
|
||||
m_layoutDirection = LocalizationService.GetInstance().GetFlowDirection();
|
||||
m_FlowDirectionHorizontalAlignment = m_layoutDirection == FlowDirection.RightToLeft ? HorizontalAlignment.Right : HorizontalAlignment.Left;
|
||||
|
||||
this.InitializeComponent();
|
||||
|
||||
// adding ESC key shortcut binding to clear button
|
||||
ClearEntryButtonPos0.SetValue(Common.KeyboardShortcutManager.VirtualKeyProperty, Common.MyVirtualKey.Escape);
|
||||
|
||||
// Is currency symbol preference set to right side
|
||||
bool preferRight = LocalizationSettings.GetInstance().GetCurrencySymbolPrecedence() == 0;
|
||||
VisualStateManager.GoToState(this, preferRight ? "CurrencySymbolRightState" : "CurrencySymbolLeftState", false);
|
||||
|
||||
var userSettings = new UISettings();
|
||||
m_isAnimationEnabled = userSettings.AnimationsEnabled;
|
||||
|
||||
var resLoader = AppResourceProvider.GetInstance();
|
||||
m_chargesMayApplyText = resLoader.GetResourceString("DataChargesMayApply");
|
||||
m_failedToRefreshText = resLoader.GetResourceString("FailedToRefresh");
|
||||
|
||||
InitializeOfflineStatusTextBlock();
|
||||
|
||||
// TODO UNO: m_resultsFlyout = (MenuFlyout) (Resources["CalculationResultContextMenu"]);
|
||||
// CopyMenuItem.Text = resLoader.GetResourceString("copyMenuItem");
|
||||
// PasteMenuItem.Text = resLoader.GetResourceString("pasteMenuItem");
|
||||
}
|
||||
|
||||
void OnPropertyChanged( object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
String propertyName = e.PropertyName;
|
||||
if (propertyName == UnitConverterViewModel.NetworkBehaviorPropertyName || propertyName == UnitConverterViewModel.CurrencyDataLoadFailedPropertyName)
|
||||
{
|
||||
OnNetworkBehaviorChanged();
|
||||
}
|
||||
else if (propertyName == UnitConverterViewModel.CurrencyDataIsWeekOldPropertyName)
|
||||
{
|
||||
SetCurrencyTimestampFontWeight();
|
||||
}
|
||||
else if (propertyName == UnitConverterViewModel.IsCurrencyLoadingVisiblePropertyName)
|
||||
{
|
||||
OnIsDisplayVisibleChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void OnNetworkBehaviorChanged()
|
||||
{
|
||||
switch (Model.NetworkBehavior)
|
||||
{
|
||||
case NetworkAccessBehavior.Normal:
|
||||
OnNormalNetworkAccess();
|
||||
break;
|
||||
case NetworkAccessBehavior.OptIn:
|
||||
OnOptInNetworkAccess();
|
||||
break;
|
||||
case NetworkAccessBehavior.Offline:
|
||||
OnOfflineNetworkAccess();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void OnNormalNetworkAccess()
|
||||
{
|
||||
CurrencyRefreshBlockControl.Visibility = Visibility.Visible;
|
||||
OfflineBlock.Visibility = Visibility.Collapsed;
|
||||
|
||||
if (Model.CurrencyDataLoadFailed)
|
||||
{
|
||||
SetFailedToRefreshStatus();
|
||||
}
|
||||
else
|
||||
{
|
||||
SetNormalCurrencyStatus();
|
||||
}
|
||||
}
|
||||
|
||||
void OnOptInNetworkAccess()
|
||||
{
|
||||
CurrencyRefreshBlockControl.Visibility = Visibility.Visible;
|
||||
OfflineBlock.Visibility = Visibility.Collapsed;
|
||||
|
||||
if (m_meteredConnectionOverride && Model.CurrencyDataLoadFailed)
|
||||
{
|
||||
SetFailedToRefreshStatus();
|
||||
}
|
||||
else
|
||||
{
|
||||
SetChargesMayApplyStatus();
|
||||
}
|
||||
}
|
||||
|
||||
void OnOfflineNetworkAccess()
|
||||
{
|
||||
CurrencyRefreshBlockControl.Visibility = Visibility.Collapsed;
|
||||
OfflineBlock.Visibility = Visibility.Visible;
|
||||
}
|
||||
|
||||
void SetNormalCurrencyStatus()
|
||||
{
|
||||
CurrencySecondaryStatus.Text = "";
|
||||
}
|
||||
|
||||
void SetChargesMayApplyStatus()
|
||||
{
|
||||
VisualStateManager.GoToState(this, "ChargesMayApplyCurrencyStatus", false);
|
||||
CurrencySecondaryStatus.Text = m_chargesMayApplyText;
|
||||
}
|
||||
|
||||
void SetFailedToRefreshStatus()
|
||||
{
|
||||
VisualStateManager.GoToState(this, "FailedCurrencyStatus", false);
|
||||
CurrencySecondaryStatus.Text = m_failedToRefreshText;
|
||||
}
|
||||
|
||||
void InitializeOfflineStatusTextBlock()
|
||||
{
|
||||
var resProvider = AppResourceProvider.GetInstance();
|
||||
string offlineStatusHyperlinkText = resProvider.GetResourceString("OfflineStatusHyperlinkText");
|
||||
|
||||
// The resource string has the 'NetworkSettings' hyperlink wrapped with '%HL%'.
|
||||
// Break the string and assign pieces appropriately.
|
||||
string delimiter = "%HL%" ;
|
||||
int delimiterLength = delimiter.Length;
|
||||
|
||||
// Find the delimiters.
|
||||
int firstSplitPosition = offlineStatusHyperlinkText.find(delimiter, 0);
|
||||
Debug.Assert(firstSplitPosition != "".npos());
|
||||
int secondSplitPosition = offlineStatusHyperlinkText.find(delimiter, firstSplitPosition + 1);
|
||||
Debug.Assert(secondSplitPosition != "".npos());
|
||||
int hyperlinkTextLength = secondSplitPosition - (firstSplitPosition + delimiterLength);
|
||||
|
||||
// Assign pieces.
|
||||
var offlineStatusTextBeforeHyperlink = offlineStatusHyperlinkText.substr(0, firstSplitPosition);
|
||||
var offlineStatusTextLink = offlineStatusHyperlinkText.substr(firstSplitPosition + delimiterLength, hyperlinkTextLength);
|
||||
var offlineStatusTextAfterHyperlink = offlineStatusHyperlinkText.substr(secondSplitPosition + delimiterLength);
|
||||
|
||||
OfflineRunBeforeLink.Text = offlineStatusTextBeforeHyperlink;
|
||||
OfflineRunLink.Text = offlineStatusTextLink;
|
||||
OfflineRunAfterLink.Text = offlineStatusTextAfterHyperlink;
|
||||
|
||||
AutomationProperties.SetName(OfflineBlock, offlineStatusTextBeforeHyperlink + " " + offlineStatusTextLink + " " + offlineStatusTextAfterHyperlink);
|
||||
}
|
||||
|
||||
void SetCurrencyTimestampFontWeight()
|
||||
{
|
||||
if (Model.CurrencyDataIsWeekOld)
|
||||
{
|
||||
VisualStateManager.GoToState(this, "WeekOldTimestamp", false);
|
||||
}
|
||||
else
|
||||
{
|
||||
VisualStateManager.GoToState(this, "DefaultTimestamp", false);
|
||||
}
|
||||
}
|
||||
|
||||
void OnValueKeyDown(object sender, Windows.UI.Xaml.Input.KeyRoutedEventArgs e)
|
||||
{
|
||||
if (e.Key == VirtualKey.Space)
|
||||
{
|
||||
OnValueSelected(sender);
|
||||
}
|
||||
}
|
||||
|
||||
void OnContextRequested(UIElement sender, ContextRequestedEventArgs e)
|
||||
{
|
||||
OnValueSelected(sender);
|
||||
var requestedElement = sender as FrameworkElement;
|
||||
|
||||
// TODO UNO
|
||||
//PasteMenuItem.IsEnabled = CopyPasteManager.HasStringToPaste();
|
||||
|
||||
Point point;
|
||||
if (e.TryGetPosition(requestedElement, out point))
|
||||
{
|
||||
m_resultsFlyout.ShowAt(requestedElement, point);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Not invoked via pointer, so let XAML choose a default location.
|
||||
m_resultsFlyout.ShowAt(requestedElement);
|
||||
}
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
void OnContextCanceled(UIElement sender, RoutedEventArgs e)
|
||||
{
|
||||
m_resultsFlyout.Hide();
|
||||
}
|
||||
|
||||
void OnCopyMenuItemClicked( object sender, RoutedEventArgs e)
|
||||
{
|
||||
var calcResult = (m_resultsFlyout.Target) as CalculationResult;
|
||||
CopyPasteManager.CopyToClipboard(calcResult.GetRawDisplayValue());
|
||||
}
|
||||
|
||||
async void OnPasteMenuItemClicked( object sender, RoutedEventArgs e)
|
||||
{
|
||||
var pastedString = await CopyPasteManager.GetStringToPaste(Model.Mode, CategoryGroupType.Converter, default(int), default(int));
|
||||
Model.OnPaste(pastedString, Model.Mode);
|
||||
}
|
||||
|
||||
public void AnimateConverter()
|
||||
{
|
||||
if (App.IsAnimationEnabled())
|
||||
{
|
||||
AnimationStory.Begin();
|
||||
}
|
||||
}
|
||||
|
||||
void OnValueSelected( object sender)
|
||||
{
|
||||
var value = (CalculationResult) sender;
|
||||
// update the font size since the font is changed to bold
|
||||
value.UpdateTextState();
|
||||
((UnitConverterViewModel) this.DataContext).OnValueActivated(value);
|
||||
}
|
||||
|
||||
void UpdateDropDownState( object sender, object e)
|
||||
{
|
||||
((UnitConverterViewModel)this.DataContext).IsDropDownOpen = (Units1.IsDropDownOpen) || (Units2.IsDropDownOpen);
|
||||
// TODO UNO: KeyboardShortcutManager.UpdateDropDownState((Units1.IsDropDownOpen) || (Units2.IsDropDownOpen));
|
||||
}
|
||||
|
||||
void OnLoaded(object sender, RoutedEventArgs args)
|
||||
{
|
||||
}
|
||||
|
||||
public void SetDefaultFocus()
|
||||
{
|
||||
CalculatorList<Control> focusPrecedence = new CalculatorList<Control>{ Value1, CurrencyRefreshBlockControl, OfflineBlock, ClearEntryButtonPos0 };
|
||||
|
||||
foreach (Control control in focusPrecedence)
|
||||
{
|
||||
if (control.Focus(FocusState.Programmatic))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CurrencyRefreshButton_Click( object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (Model.NetworkBehavior == NetworkAccessBehavior.OptIn)
|
||||
{
|
||||
m_meteredConnectionOverride = true;
|
||||
}
|
||||
|
||||
Model.RefreshCurrencyRatios();
|
||||
}
|
||||
|
||||
void OnDataContextChanged( DependencyObject sender, DataContextChangedEventArgs args)
|
||||
{
|
||||
Model.PropertyChanged -= OnPropertyChanged;
|
||||
|
||||
Model.PropertyChanged += new PropertyChangedEventHandler(OnPropertyChanged);
|
||||
|
||||
OnNetworkBehaviorChanged();
|
||||
}
|
||||
|
||||
void Units1_IsEnabledChanged(object sender, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if ((Units1.Visibility == Visibility.Visible) && Units1.IsEnabled)
|
||||
{
|
||||
SetDefaultFocus();
|
||||
}
|
||||
}
|
||||
|
||||
void OnIsDisplayVisibleChanged()
|
||||
{
|
||||
if (Model.IsCurrencyLoadingVisible)
|
||||
{
|
||||
StartProgressRingWithDelay();
|
||||
}
|
||||
else
|
||||
{
|
||||
HideProgressRing();
|
||||
|
||||
if (m_isAnimationEnabled && Model.IsCurrencyCurrentCategory && !Model.CurrencyTimestamp.IsEmpty())
|
||||
{
|
||||
TimestampFadeInAnimation.Begin();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void StartProgressRingWithDelay()
|
||||
{
|
||||
HideProgressRing();
|
||||
|
||||
TimeSpan delay = TimeSpan.FromMilliseconds(DURATION_500_MS);
|
||||
|
||||
m_delayTimer = new DispatcherTimer();
|
||||
m_delayTimer.Interval = delay;
|
||||
m_delayTimer.Tick += new EventHandler<object> (OnDelayTimerTick);
|
||||
|
||||
m_delayTimer.Start();
|
||||
}
|
||||
|
||||
void OnDelayTimerTick(object sender, object e)
|
||||
{
|
||||
CurrencyLoadingProgressRing.IsActive = true;
|
||||
m_delayTimer.Stop();
|
||||
}
|
||||
|
||||
void HideProgressRing()
|
||||
{
|
||||
if (m_delayTimer != null)
|
||||
{
|
||||
m_delayTimer.Stop();
|
||||
}
|
||||
|
||||
CurrencyLoadingProgressRing.IsActive = false;
|
||||
}
|
||||
|
||||
// The function will make sure the UI will have enough space to display supplementary results and currency information
|
||||
void SupplementaryResultsPanelInGrid_SizeChanged(object sender, Windows.UI.Xaml.SizeChangedEventArgs e)
|
||||
{
|
||||
// We add 0.01 to be sure to not create an infinite loop with SizeChanged events cascading due to float approximation
|
||||
RowDltrUnits.MinHeight = Math.Max(48.0, e.NewSize.Height + 0.01);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
45
src/Calculator.Shared/_adapters/StringExtensions.cs
Normal file
45
src/Calculator.Shared/_adapters/StringExtensions.cs
Normal file
|
@ -0,0 +1,45 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace Calculator
|
||||
{
|
||||
public static class StringExtensions
|
||||
{
|
||||
private const int _npos = -1;
|
||||
|
||||
public static char back(this string str) => str.Last();
|
||||
public static char front(this string str) => str.First();
|
||||
public static int length(this string str) => str.Length;
|
||||
public static char at(this string str, int index) => str[index];
|
||||
public static bool empty(this string str) => string.IsNullOrEmpty(str);
|
||||
public static bool IsEmpty(this string str) => string.IsNullOrEmpty(str);
|
||||
public static int npos(this string str) => _npos;
|
||||
public static int size(this string str) => str.Length;
|
||||
public static int find(this string str, char c) => str.IndexOf(c);
|
||||
public static int find(this string str, char c, int startIndex) => str.IndexOf(c, startIndex);
|
||||
public static int find(this string str, string c) => str.IndexOf(c);
|
||||
public static int find(this string str, string c, int startIndex) => str.IndexOf(c, startIndex);
|
||||
|
||||
public static string substr(this string str, int pos = 0, int len = _npos)
|
||||
{
|
||||
if (pos == str.Length)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
if (pos > str.Length)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(pos));
|
||||
}
|
||||
|
||||
if (len == _npos)
|
||||
{
|
||||
return str.Substring(pos);
|
||||
}
|
||||
else
|
||||
{
|
||||
return str.Substring(pos, Math.Min(len, str.Length - pos));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -12,6 +12,7 @@
|
|||
<NuGetPackageImportStamp>
|
||||
</NuGetPackageImportStamp>
|
||||
<ResourcesDirectory>..\Calculator.Shared\Strings</ResourcesDirectory>
|
||||
<LangVersion>7.3</LangVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|iPhoneSimulator' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue