Enable DateCalculator

This commit is contained in:
Dr.Rx 2019-05-15 18:13:07 -04:00
commit 84599cfe72
11 changed files with 1423 additions and 681 deletions

View file

@ -39,6 +39,7 @@
<Compile Include="$(MSBuildThisFileDirectory)Common\CalculatorButtonUser.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Common\CalculatorDisplay.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Common\CopyPasteManager.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Common\DateCalculator.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Common\DelegateCommand.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Common\DisplayExpressionToken.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Common\EngineResourceProvider.cs" />
@ -48,6 +49,7 @@
<Compile Include="$(MSBuildThisFileDirectory)Common\MyVirtualKey.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Common\NavCategory.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Common\TitleBarHelper.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Common\TraceLogger.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Common\Utils.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Controls\CalculationResult.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Controls\CalculationResultAutomationPeer.cs" />

View file

@ -0,0 +1,377 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using System.Text;
using Windows.Globalization;
namespace CalculatorApp.Common.DateCalculation
{
[Flags]
public enum DateUnit
{
Year = 0x01,
Month = 0x02,
Week = 0x04,
Day = 0x08
};
// Struct to store the difference between two Dates in the form of Years, Months , Weeks
public struct DateDifference
{
public int year;
public int month;
public int week;
public int day;
};
public class DateCalculationEngine
{
const ulong c_millisecond = 10000;
const ulong c_second = 1000 * c_millisecond;
const ulong c_minute = 60 * c_second;
const ulong c_hour = 60 * c_minute;
const ulong c_day = 24 * c_hour;
const int c_unitsOfDate = 4; // Units Year,Month,Week,Day
const int c_unitsGreaterThanDays = 3; // Units Greater than Days (Year/Month/Week) 3
const int c_daysInWeek = 7;
private Calendar m_calendar;
public DateCalculationEngine(string calendarIdentifier)
{
m_calendar = new Calendar();
m_calendar.ChangeTimeZone("UTC");
m_calendar.ChangeCalendarSystem(calendarIdentifier);
}
// Adding Duration to a Date
// Returns: True if function succeeds to calculate the date else returns False
public bool AddDuration( DateTime startDate, DateDifference duration, out DateTime endDate)
{
var currentCalendarSystem = m_calendar.GetCalendarSystem();
try
{
m_calendar.SetDateTime(startDate);
// The Japanese Era system can have multiple year partitions within the same year.
// For example, April 30, 2019 is denoted April 30, Heisei 31; May 1, 2019 is denoted as May 1, Reiwa 1.
// The Calendar treats Heisei 31 and Reiwa 1 as separate years, which results in some unexpected behaviors where subtracting a year from Reiwa 1 results
// in a date in Heisei 31. To provide the expected result across era boundaries, we first convert the Japanese era system to a Gregorian system, do date
// math, and then convert back to the Japanese era system. This works because the Japanese era system maintains the same year/month boundaries and
// durations as the Gregorian system and is only different in display value.
if (currentCalendarSystem == CalendarIdentifiers.Japanese)
{
m_calendar.ChangeCalendarSystem(CalendarIdentifiers.Gregorian);
}
if (duration.year != 0)
{
m_calendar.AddYears(duration.year);
}
if (duration.month != 0)
{
m_calendar.AddMonths(duration.month);
}
if (duration.day != 0)
{
m_calendar.AddDays(duration.day);
}
endDate = m_calendar.GetDateTime().DateTime;
}
catch (ArgumentException ex)
{
// ensure that we revert to the correct calendar system
m_calendar.ChangeCalendarSystem(currentCalendarSystem);
// Do nothing
endDate = default(DateTime);
return false;
}
m_calendar.ChangeCalendarSystem(currentCalendarSystem);
return true;
}
// Subtracting Duration from a Date
// Returns: True if function succeeds to calculate the date else returns False
public bool SubtractDuration( DateTime startDate, DateDifference duration, out DateTime endDate)
{
var currentCalendarSystem = m_calendar.GetCalendarSystem();
// For Subtract the Algorithm is different than Add. Here the smaller units are subtracted first
// and then the larger units.
try
{
m_calendar.SetDateTime(startDate);
// The Japanese Era system can have multiple year partitions within the same year.
// For example, April 30, 2019 is denoted April 30, Heisei 31; May 1, 2019 is denoted as May 1, Reiwa 1.
// The Calendar treats Heisei 31 and Reiwa 1 as separate years, which results in some unexpected behaviors where subtracting a year from Reiwa 1 results
// in a date in Heisei 31. To provide the expected result across era boundaries, we first convert the Japanese era system to a Gregorian system, do date
// math, and then convert back to the Japanese era system. This works because the Japanese era system maintains the same year/month boundaries and
// durations as the Gregorian system and is only different in display value.
if (currentCalendarSystem == CalendarIdentifiers.Japanese)
{
m_calendar.ChangeCalendarSystem(CalendarIdentifiers.Gregorian);
}
if (duration.day != 0)
{
m_calendar.AddDays(-duration.day);
}
if (duration.month != 0)
{
m_calendar.AddMonths(-duration.month);
}
if (duration.year != 0)
{
m_calendar.AddYears(-duration.year);
}
endDate = m_calendar.GetDateTime().DateTime;
}
catch (ArgumentException ex)
{
// ensure that we revert to the correct calendar system
m_calendar.ChangeCalendarSystem(currentCalendarSystem);
// Do nothing
endDate = default(DateTime);
return false;
}
m_calendar.ChangeCalendarSystem(currentCalendarSystem);
// Check that the UniversalTime value is not negative
return (endDate.ToUniversalTime().Ticks >= 0);
}
// Calculate the difference between two dates
public void GetDateDifference( DateTime date1, DateTime date2, DateUnit outputFormat, out DateDifference difference)
{
DateTime startDate;
DateTime endDate;
DateTime pivotDate;
DateTime tempPivotDate;
uint daysDiff = 0;
uint[] differenceInDates = new uint[c_unitsOfDate];
if (date1.ToUniversalTime() < date2.ToUniversalTime())
{
startDate = date1;
endDate = date2;
}
else
{
startDate = date2;
endDate = date1;
}
pivotDate = startDate;
daysDiff = (uint)GetDifferenceInDays(startDate, endDate);
// If output has units other than days
// 0th bit: Year, 1st bit: Month, 2nd bit: Week, 3rd bit: Day
if (((int)(outputFormat) & 7) != 0)
{
uint daysInMonth;
uint approximateDaysInYear;
// If we're unable to calculate the days-in-month or days-in-year, we'll leave the values at 0.
if (TryGetCalendarDaysInMonth(startDate, out daysInMonth) && TryGetCalendarDaysInYear(endDate, out approximateDaysInYear))
{
uint[] daysIn = new uint[c_unitsOfDate] { approximateDaysInYear, daysInMonth, c_daysInWeek, 1 };
for (int unitIndex = 0; unitIndex < c_unitsGreaterThanDays; unitIndex++)
{
tempPivotDate = pivotDate;
// Check if the bit flag is set for the date unit
DateUnit dateUnit = (DateUnit)(1 << unitIndex);
if ((int)(outputFormat & dateUnit) != 0)
{
bool isEndDateHit = false;
differenceInDates[unitIndex] = (daysDiff / daysIn[unitIndex]);
if (differenceInDates[unitIndex] != 0)
{
try
{
pivotDate = AdjustCalendarDate(pivotDate, dateUnit, (int)(differenceInDates[unitIndex]));
}
catch (ArgumentException)
{
// Operation failed due to out of bound result
// Do nothing
differenceInDates[unitIndex] = 0;
}
}
int tempDaysDiff;
do
{
tempDaysDiff = GetDifferenceInDays(pivotDate, endDate);
if (tempDaysDiff < 0)
{
// pivotDate has gone over the end date; start from the beginning of this unit
differenceInDates[unitIndex] -= 1;
pivotDate = tempPivotDate;
pivotDate = AdjustCalendarDate(pivotDate, dateUnit, (int)(differenceInDates[unitIndex]));
isEndDateHit = true;
}
else if (tempDaysDiff > 0)
{
if (isEndDateHit)
{
// This is the closest the pivot can get to the end date for this unit
break;
}
// pivotDate is still below the end date
try
{
pivotDate = AdjustCalendarDate(pivotDate, dateUnit, 1);
differenceInDates[unitIndex] += 1;
}
catch (ArgumentException)
{
// handling for 31st Dec, 9999 last valid date
// Do nothing - break out
break;
}
}
} while (tempDaysDiff != 0); // dates are the same - exit the loop
tempPivotDate = AdjustCalendarDate(tempPivotDate, dateUnit, (int)(differenceInDates[unitIndex]));
pivotDate = tempPivotDate;
daysDiff = (uint)GetDifferenceInDays(pivotDate, endDate);
}
}
}
}
differenceInDates[3] = daysDiff;
difference.year = (int)differenceInDates[0];
difference.month = (int)differenceInDates[1];
difference.week = (int)differenceInDates[2];
difference.day = (int)differenceInDates[3];
}
// Private Methods
// Gets number of days between the two date time values
int GetDifferenceInDays(DateTime date1, DateTime date2)
{
// A tick is defined as the number of 100 nanoseconds
long ticksDifference = date2.ToUniversalTime().Ticks - date1.ToUniversalTime().Ticks;
return (int)(ticksDifference / (long)(c_day));
}
// Gets number of Calendar days in the month in which this date falls.
// Returns true if successful, false otherwise.
bool TryGetCalendarDaysInMonth( DateTime date, out uint daysInMonth)
{
daysInMonth = 0;
bool result = false;
m_calendar.SetDateTime(date);
// NumberOfDaysInThisMonth returns -1 if unknown.
int daysInThisMonth = m_calendar.NumberOfDaysInThisMonth;
if (daysInThisMonth != -1)
{
daysInMonth = (uint)(daysInThisMonth);
result = true;
}
return result;
}
// Gets number of Calendar days in the year in which this date falls.
// Returns true if successful, false otherwise.
bool TryGetCalendarDaysInYear( DateTime date, out uint daysInYear)
{
daysInYear = 0;
bool result = false;
uint days = 0;
m_calendar.SetDateTime(date);
// NumberOfMonthsInThisYear returns -1 if unknown.
int monthsInYear = m_calendar.NumberOfMonthsInThisYear;
if (monthsInYear != -1)
{
bool monthResult = true;
// Not all years begin with Month 1.
int firstMonthThisYear = m_calendar.FirstMonthInThisYear;
for (int month = 0; month < monthsInYear; month++)
{
m_calendar.Month = firstMonthThisYear + month;
// NumberOfDaysInThisMonth returns -1 if unknown.
int daysInMonth = m_calendar.NumberOfDaysInThisMonth;
if (daysInMonth == -1)
{
monthResult = false;
break;
}
days += (uint)daysInMonth;
}
if (monthResult)
{
daysInYear = days;
result = true;
}
}
return result;
}
// Adds/Subtracts certain value for a particular date unit
DateTime AdjustCalendarDate(DateTime date, DateUnit dateUnit, int difference)
{
m_calendar.SetDateTime(date);
// The Japanese Era system can have multiple year partitions within the same year.
// For example, April 30, 2019 is denoted April 30, Heisei 31; May 1, 2019 is denoted as May 1, Reiwa 1.
// The Calendar treats Heisei 31 and Reiwa 1 as separate years, which results in some unexpected behaviors where subtracting a year from Reiwa 1 results in
// a date in Heisei 31. To provide the expected result across era boundaries, we first convert the Japanese era system to a Gregorian system, do date math,
// and then convert back to the Japanese era system. This works because the Japanese era system maintains the same year/month boundaries and durations as
// the Gregorian system and is only different in display value.
var currentCalendarSystem = m_calendar.GetCalendarSystem();
if (currentCalendarSystem == CalendarIdentifiers.Japanese)
{
m_calendar.ChangeCalendarSystem(CalendarIdentifiers.Gregorian);
}
switch (dateUnit)
{
case DateUnit.Year:
m_calendar.AddYears(difference);
break;
case DateUnit.Month:
m_calendar.AddMonths(difference);
break;
case DateUnit.Week:
m_calendar.AddWeeks(difference);
break;
}
m_calendar.ChangeCalendarSystem(currentCalendarSystem);
return m_calendar.GetDateTime().DateTime;
}
}
}

View file

@ -379,7 +379,7 @@ namespace CalculatorApp.Common
// as configured by running intl.cpl.
//
// This helper function creates a DateTimeFormatter with a TwentyFour hour clock
DateTimeFormatter GetRegionalSettingsAwareDateTimeFormatter( string format)
public static DateTimeFormatter GetRegionalSettingsAwareDateTimeFormatter( string format)
{
IEnumerable<String> languageIdentifiers = GetLanguageIdentifiers();
if (languageIdentifiers == null)
@ -392,75 +392,39 @@ namespace CalculatorApp.Common
// If successful, returns a formatter that respects the user's regional format settings,
// as configured by running intl.cpl.
DateTimeFormatter GetRegionalSettingsAwareDateTimeFormatter( string format, string calendarIdentifier, string clockIdentifier)
public static DateTimeFormatter GetRegionalSettingsAwareDateTimeFormatter( string format, string calendarIdentifier, string clockIdentifier)
{
// UNO TODO
//IIterable<String> languageIdentifiers = GetLanguageIdentifiers();
//if (languageIdentifiers == null)
//{
// languageIdentifiers = ApplicationLanguages.Languages;
//}
IEnumerable<string> languageIdentifiers = GetLanguageIdentifiers();
if (languageIdentifiers == null)
{
languageIdentifiers = ApplicationLanguages.Languages;
}
//return new DateTimeFormatter(format, languageIdentifiers, GlobalizationPerences.HomeGeographicRegion, calendarIdentifier, clockIdentifier);
throw new NotImplementedException();
return new DateTimeFormatter(format, languageIdentifiers, GlobalizationPreferences.HomeGeographicRegion, calendarIdentifier, clockIdentifier);
}
public CurrencyFormatter GetRegionalSettingsAwareCurrencyFormatter()
public static CurrencyFormatter GetRegionalSettingsAwareCurrencyFormatter()
{
// UNO TODO
//string userCurrency =
// (GlobalizationPreferences.Currencies.Size > 0) ? GlobalizationPreferences.Currencies.GetAt(0) : string(DefaultCurrencyCode.data());
string userCurrency =
(GlobalizationPreferences.Currencies.Count > 0) ? GlobalizationPreferences.Currencies[0] : DefaultCurrencyCode;
//IIterable<String> languageIdentifiers = GetLanguageIdentifiers();
//if (languageIdentifiers == null)
//{
// languageIdentifiers = ApplicationLanguages.Languages;
//}
IEnumerable<string> languageIdentifiers = GetLanguageIdentifiers();
if (languageIdentifiers == null)
{
languageIdentifiers = ApplicationLanguages.Languages;
}
//var currencyFormatter = new CurrencyFormatter(userCurrency, languageIdentifiers, GlobalizationPerences.HomeGeographicRegion);
var currencyFormatter = new CurrencyFormatter(userCurrency, languageIdentifiers, GlobalizationPreferences.HomeGeographicRegion);
//int fractionDigits = LocalizationSettings.GetInstance().GetCurrencyTrailingDigits();
//currencyFormatter.FractionDigits = fractionDigits;
int fractionDigits = LocalizationSettings.GetInstance().GetCurrencyTrailingDigits();
currencyFormatter.FractionDigits = fractionDigits;
//return currencyFormatter;
throw new NotImplementedException();
return currencyFormatter;
}
static IEnumerable<String> GetLanguageIdentifiers()
{
#if !HAS_UNO
//char currentLocale[LOCALE_NAME_MAX_LENGTH] = {};
//int result = GetUserDefaultLocaleName(currentLocale, LOCALE_NAME_MAX_LENGTH);
//if (result != 0)
//{
// // GetUserDefaultLocaleName may return an invalid bcp47 language tag with trailing non-BCP47 friendly characters,
// // which if present would start with an underscore, for example sort order
// // (see https://msdn.microsoft.com/en-us/library/windows/desktop/dd373814(v=vs.85).aspx).
// // Therefore, if there is an underscore in the locale name, trim all characters from the underscore onwards.
// WCHAR* underscore = wcschr(currentLocale, '_');
// if (underscore != null)
// {
// *underscore = '\0';
// }
// string localestring = new String(currentLocale);
// // validate if the locale we have is valid
// // otherwise we fallback to the default.
// if (Language.IsWellFormed(localeString))
// {
// var languageList = new Vector<String>();
// languageList.Append(localeString);
// return languageList;
// }
//}
//return null;
yield break;
#else
yield break;
#endif
{
return GlobalizationPreferences.Languages;
}
// Resources for the engine use numbers as keys. It's inconvenient, but also difficult to

View file

@ -128,17 +128,16 @@ namespace CalculatorApp
m_digitSymbols[i] = i.ToString(NumberFormatInfo.CurrentInfo)[0];
}
// As CalcEngine only supports the first character of the decimal separator,
// Only first character of the decimal separator string is supported.
m_decimalSeparator = NumberFormatInfo.CurrentInfo.NumberDecimalSeparator[0];
// As CalcEngine only supports the first character of the decimal separator,
// Only first character of the decimal separator string is supported.
m_decimalSeparator = NumberFormatInfo.CurrentInfo.NumberDecimalSeparator[0];
m_numberGroupSeparator = NumberFormatInfo.CurrentInfo.NumberGroupSeparator[0];
m_numberGrouping = ""; // UNO TODO https://docs.microsoft.com/en-us/windows/desktop/Intl/locale-sgrouping
m_listSeparator = CultureInfo.CurrentCulture.TextInfo.ListSeparator;
m_currencyTrailingDigits = NumberFormatInfo.CurrentInfo.CurrencyDecimalDigits;
m_currencySymbolPrecedence = ~(NumberFormatInfo.CurrentInfo.CurrencyPositivePattern) & 1;
m_calendarIdentifier = "";//CultureInfo.CurrentCulture.DateTimeFormat.Calendar.ToString();
m_resolvedName = CultureInfo.CurrentCulture.Name;
m_calendarIdentifier = new Windows.Globalization.Calendar().GetCalendarSystem();
m_firstDayOfWeek = (Windows.Globalization.DayOfWeek)CultureInfo.CurrentCulture.DateTimeFormat.FirstDayOfWeek;
#endif
}
@ -155,7 +154,7 @@ namespace CalculatorApp
return m_localizationSettings;
}
string GetLocaleName()
public string GetLocaleName()
{
return m_resolvedName;
}
@ -326,7 +325,7 @@ namespace CalculatorApp
return m_listSeparator;
}
Windows.Globalization.DayOfWeek GetFirstDayOfWeek()
public Windows.Globalization.DayOfWeek GetFirstDayOfWeek()
{
return m_firstDayOfWeek;
}

View file

@ -0,0 +1,81 @@
using System;
using System.Collections.Generic;
using System.Text;
using Windows.Globalization;
using CalculatorApp.Common;
namespace CalculatorApp
{
public class TraceLogger
{
private static TraceLogger _instance = new TraceLogger();
public static TraceLogger GetInstance() => _instance;
public bool GetTraceLoggingProviderEnabled() => false;
public void LogAppLaunchStart() {}
public void LogAppLaunchComplete() {}
public void LogAppResumeComplete() {}
//public void LogOnAppLaunch(std::wstring_view previousExecutionState) {}
public void LogMemoryClearAll(int i) {}
public void LogBitFlipPaneClicked() {}
public void LogBitFlipUsed() {}
public void LogHistoryBodyOpened() {}
public void LogHistoryItemLoadBegin() {}
public void LogHistoryItemLoadEnd(uint i) {}
public void LogHistoryFlyoutOpenBegin(uint i) {}
public void LogHistoryFlyoutOpenEnd(int i) {}
public void LogCalculatorModeViewed(ViewMode mode, int i) {}
public void LogDateCalculatorModeViewed(ViewMode mode, int i) {}
public void LogConverterModeViewed(ViewMode mode, int i) {}
public void LogModeChangeBegin(ViewMode oldMode, ViewMode newMode, int i) {}
public void LogModeChangeEnd(ViewMode mode, int i) {}
public void LogClearHistory() {}
public void InsertintoMemoryMap(int i, bool b1, bool b2, bool b3) {}
public void UpdateMemoryMap(int i1, int i2, bool b1, bool b2, bool b3) {}
public void DeleteFromMemoryMap(int i1, int i2) {}
public void LogMemoryUsed(int i1, uint i2, bool b1, bool b2, bool b3, uint i4) {}
public void LogMultipleMemoryUsed(uint i1, uint i2) {}
public void LogSingleMemoryUsed(uint i) {}
//public void LogSharedMemoryUsed(std::wstring_view, std::wstring_view, uint i) {}
public void LogMemoryBodyOpened() {}
public void LogMemoryFlyoutOpenBegin(uint i) {}
//public void LogDebug(std::wstring_view debugData) {}
public void LogMemoryFlyoutOpenEnd(uint i) {}
//public void LogInvalidPastedInputOccurred(std::wstring_view reason, ViewMode mode, int ProgrammerNumberBase, int bitLengthType) {}
public void LogValidInputPasted(ViewMode mode) {}
public void UpdateFunctionUsage(int func) {}
public void LogFunctionUsage(int i) {}
public void InitFunctionLogArray() {}
public void LogBitLengthButtonUsed(int windowId) {}
public void LogRadixButtonUsed(int windowId) {}
public void LogAngleButtonUsed(int windowId) {}
public void LogHypButtonUsed(int windowId) {}
public void LogNewWindowCreationBegin(int windowId) {}
public void LogNewWindowCreationEnd(int windowId) {}
//public void LogError(std::wstring_view errorString) {}
public void LogPrelaunchedAppActivatedByUser() {}
public void LogAppPrelaunchedBySystem() {}
//public void UpdateWindowCount(size_t windowCount) {}
public bool UpdateWindowIdLog(int windowId) => true;
public void LogMaxWindowCount() {}
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 LogAboutFlyoutOpened() {}
public void LogNavBarOpened() {}
public void LogViewClosingTelemetry(int i) {}
public void LogCoreWindowWasNull() {}
// Trace methods for Date Calculator usage
public void LogDateDifferenceModeUsed(int windowId) {}
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) {}
}
}

View file

@ -35,9 +35,8 @@ namespace CalculatorApp.ViewModel
private StandardCalculatorViewModel m_CalculatorViewModel;
public StandardCalculatorViewModel CalculatorViewModel { get => m_CalculatorViewModel; set { m_CalculatorViewModel = value; RaisePropertyChanged("CalculatorViewModel"); } }
// UNO TODO
//private DateCalculatorViewModel m_DateCalcViewModel;
//public DateCalculatorViewModel DateCalcViewModel { get => m_DateCalcViewModel; set { m_DateCalcViewModel = value; RaisePropertyChanged("DateCalcViewModel"); } }
private DateCalculatorViewModel m_DateCalcViewModel;
public DateCalculatorViewModel DateCalcViewModel { get => m_DateCalcViewModel; set { m_DateCalcViewModel = value; RaisePropertyChanged("DateCalcViewModel"); } }
// UNO TODO
@ -160,12 +159,11 @@ namespace CalculatorApp.ViewModel
else if (NavCategory.IsDateCalculatorViewMode(m_mode))
{
// TraceLogger.GetInstance().LogDateCalculatorModeViewed(m_mode, ApplicationView.GetApplicationViewIdForWindow(CoreWindow.GetForCurrentThread()));
// UNO TODO
//if (m_DateCalcViewModel == null)
//{
// m_DateCalcViewModel = new DateCalculatorViewModel();
//}
}
if (m_DateCalcViewModel == null)
{
m_DateCalcViewModel = new DateCalculatorViewModel();
}
}
else if (NavCategory.IsConverterViewMode(m_mode))
{
// UNO TODO
@ -200,12 +198,13 @@ namespace CalculatorApp.ViewModel
//{
// ConverterViewModel.OnCopyCommand(parameter);
//}
//else if (NavCategory.IsDateCalculatorViewMode(m_mode))
//{
// DateCalcViewModel.OnCopyCommand(parameter);
//}
//else
{
if (NavCategory.IsDateCalculatorViewMode(m_mode))
{
DateCalcViewModel.OnCopyCommand(parameter);
}
else
{
CalculatorViewModel.OnCopyCommand(parameter);
}
}

File diff suppressed because it is too large Load diff

View file

@ -553,7 +553,7 @@ namespace CalculatorApp
FullscreenFlyoutClosed();
}
void CloseHistoryFlyout()
public void CloseHistoryFlyout()
{
if (m_fIsHistoryFlyoutOpen)
{
@ -561,7 +561,7 @@ namespace CalculatorApp
}
}
void CloseMemoryFlyout()
public void CloseMemoryFlyout()
{
if (m_fIsMemoryFlyoutOpen)
{

View file

@ -5,11 +5,10 @@
xmlns:converters="using:CalculatorApp.Converters"
xmlns:local="using:CalculatorApp.Views"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Loaded="OnLoaded"
mc:Ignorable="">
<!-- UNO TODO Loaded="OnLoaded"-->
<!-- UNO TODO <UserControl.Resources>
<UserControl.Resources>
<converters:BooleanNegationConverter x:Key="BooleanNegationConverter" />
<converters:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
<converters:BooleanToVisibilityNegationConverter x:Key="BooleanToVisibilityNegationConverter" />
@ -441,26 +440,26 @@
Value="False" />
</Style>
<MenuFlyout x:Key="ResultsContextMenu"
<!--TODO UNO <MenuFlyout x:Key="ResultsContextMenu"
x:Name="ResultsContextMenu">
<MenuFlyoutItem x:Name="CopyMenuItem"
x:Uid="CopyMenuItem"
Click="OnCopyMenuItemClicked"
Icon="Copy" />
</MenuFlyout>
</MenuFlyout>-->
</UserControl.Resources>
<Grid x:Name="DateCalculatorGrid"
Margin="12,0,12,0"
AutomationProperties.LandmarkType="Main">
<Grid.ColumnDefinitions>
<ColumnDefinition x:Name="C0"
Width="*" />
<ColumnDefinition x:Name="C1"
Width="0" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="1*"
MinHeight="{StaticResource HamburgerHeight}"
@ -500,29 +499,29 @@
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
--><!-- ComboBox for Date Calculation options --><!--
<!-- ComboBox for Date Calculation options -->
<ComboBox x:Name="DateCalculationOption"
x:Uid="DateCalculationOption"
Grid.Row="1"
Style="{ThemeResource DateCalculation_ComboStyle}"
SelectedIndex="0">
<ComboBoxItem x:Uid="Date_DifferenceOption"
MinWidth="276"
ContentTemplate="{StaticResource ComboBoxItemContentTemplate}"
IsSelected="{Binding IsDateDiffMode, Mode=TwoWay}" />
<ComboBoxItem x:Uid="Date_AddSubtractOption"
MinWidth="276"
ContentTemplate="{StaticResource ComboBoxItemContentTemplate}"
IsSelected="{Binding IsDateDiffMode, Converter={StaticResource BooleanNegationConverter}, Mode=TwoWay}" />
</ComboBox>
--><!-- Grid to Calculate Difference between Two Dates --><!--
<!-- Grid to Calculate Difference between Two Dates -->
<Grid x:Name="DateDiffGrid"
Grid.Row="2"
Visibility="{Binding IsDateDiffMode, Converter={StaticResource BooleanToVisibilityConverter}}">
<Grid.RowDefinitions>
<RowDefinition Height="1*"
MaxHeight="17" />
@ -543,14 +542,14 @@
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
--><!-- From Date --><!--
<!-- From Date -->
<TextBlock x:Name="Date_FromLabel"
x:Uid="Date_FromLabel"
Grid.Row="1"
Margin="0,0,0,2"
Foreground="{ThemeResource SystemControlPageTextBaseHighBrush}"
TextWrapping="Wrap" />
<CalendarDatePicker x:Name="DateDiff_FromDate"
Grid.Row="2"
Style="{StaticResource DateCalculation_CalendarPickerStyle}"
@ -559,14 +558,14 @@
Closed="CalendarFlyoutClosed"
DateChanged="FromDate_DateChanged" />
--><!-- To Date --><!--
<!-- To Date -->
<TextBlock x:Name="Date_ToLabel"
x:Uid="Date_ToLabel"
Grid.Row="4"
Margin="0,0,0,2"
Foreground="{ThemeResource SystemControlPageTextBaseHighBrush}"
TextWrapping="Wrap" />
<CalendarDatePicker x:Name="DateDiff_ToDate"
Grid.Row="5"
Margin="0,0,0,0"
@ -576,12 +575,12 @@
Closed="CalendarFlyoutClosed"
DateChanged="ToDate_DateChanged" />
--><!-- Difference Result --><!--
<!-- Difference Result -->
<TextBlock x:Uid="Date_DifferenceLabel"
Grid.Row="7"
Margin="0,0,0,0"
Foreground="{ThemeResource SystemControlPageTextBaseHighBrush}" />
<TextBlock x:Name="DateDiffAllUnitsResultLabel"
Grid.Row="8"
Style="{ThemeResource SubtitleTextBlockStyle}"
@ -590,7 +589,7 @@
AutomationProperties.Name="{Binding StrDateDiffResultAutomationName}"
ContextFlyout="{StaticResource ResultsContextMenu}"
Text="{Binding StrDateDiffResult}" />
<TextBlock Grid.Row="10"
Style="{ThemeResource BaseTextBlockStyle}"
Foreground="{ThemeResource SystemControlPageTextBaseMediumBrush}"
@ -599,7 +598,7 @@
Visibility="{Binding IsDiffInDays, Converter={StaticResource BooleanToVisibilityNegationConverter}}" />
</Grid>
--><!-- Grid for Add/Subtract Date --><!--
<!-- Grid for Add/Subtract Date -->
<Grid x:Name="AddSubtractDateGrid"
Grid.Row="2"
x:DeferLoadStrategy="Lazy"
@ -624,7 +623,8 @@
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
--><!-- From Date --><!--
<!-- From Date -->
<TextBlock x:Name="AddSubtract_Date_FromLabel"
x:Uid="Date_FromLabel"
Grid.Row="1"
@ -632,7 +632,7 @@
Style="{ThemeResource BodyTextBlockStyle}"
Foreground="{ThemeResource SystemControlPageTextBaseMediumBrush}"
TextWrapping="Wrap" />
<CalendarDatePicker x:Name="AddSubtract_FromDate"
Grid.Row="2"
Margin="0,0,0,0"
@ -655,7 +655,7 @@
VerticalAlignment="Top"
Checked="AddSubtractOption_Checked"
IsChecked="{Binding IsAddMode, Mode=TwoWay}" />
<RadioButton x:Name="SubtractOption"
x:Uid="SubtractOption"
Grid.Column="1"
@ -668,7 +668,8 @@
</Grid>
--><!-- Date Offset to be Added/Subtracted --><!--
<!-- Date Offset to be Added/Subtracted -->
<Grid x:Name="DateOffsetGrid"
Grid.Row="6">
@ -688,7 +689,7 @@
Margin="0,0,0,6"
Foreground="{ThemeResource SystemControlPageTextBaseMediumBrush}"
TextWrapping="Wrap" />
<ComboBox x:Name="YearsValue"
Grid.Row="1"
MinWidth="84"
@ -697,14 +698,14 @@
ItemsSource="{Binding OffsetValues, Mode=OneTime}"
SelectedIndex="{Binding YearsOffset, Mode=TwoWay}"
SelectionChanged="OffsetValue_Changed" />
<TextBlock x:Name="MonthsLabel"
x:Uid="MonthsLabel"
Grid.Column="1"
Margin="12,0,12,6"
Foreground="{ThemeResource SystemControlPageTextBaseMediumBrush}"
TextWrapping="Wrap" />
<ComboBox x:Name="MonthsValue"
Grid.Row="1"
Grid.Column="1"
@ -715,14 +716,14 @@
ItemsSource="{Binding OffsetValues, Mode=OneTime}"
SelectedIndex="{Binding MonthsOffset, Mode=TwoWay}"
SelectionChanged="OffsetValue_Changed" />
<TextBlock x:Name="DaysLabel"
x:Uid="DaysLabel"
Grid.Column="2"
Margin="0,0,0,6"
Foreground="{ThemeResource SystemControlPageTextBaseMediumBrush}"
TextWrapping="Wrap" />
<ComboBox x:Name="DaysValue"
Grid.Row="1"
Grid.Column="2"
@ -734,7 +735,8 @@
SelectionChanged="OffsetValue_Changed" />
</Grid>
--><!-- Resulting Date --><!--
<!-- Resulting Date -->
<TextBlock x:Uid="DateLabel"
Grid.Row="8"
Foreground="{ThemeResource SystemControlPageTextBaseMediumBrush}" />
@ -748,5 +750,5 @@
ContextFlyout="{StaticResource ResultsContextMenu}"
Text="{Binding StrDateResult}" />
</Grid>
</Grid>-->
</Grid>
</UserControl>

View file

@ -1,17 +1,19 @@
using System;
using System.Collections.Generic;
using System.IO;
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.Globalization;
using Windows.Globalization.DateTimeFormatting;
using Windows.UI.Core;
using Windows.UI.ViewManagement;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Automation;
using Windows.UI.Xaml.Automation.Peers;
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 CalculatorApp.Common;
using CalculatorApp.ViewModel;
// The User Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234236
@ -19,9 +21,207 @@ namespace CalculatorApp
{
public sealed partial class DateCalculator : UserControl
{
// We choose 2550 as the max year because CalendarDatePicker experiences clipping
// issues just after 2558. We would like 9999 but will need to wait for a platform
// fix before we use a higher max year. This platform issue is tracked by
// TODO: MSFT-9273247
const int c_maxYear = 2550;
const int c_minYear = 1601;
public DateCalculator()
{
this.InitializeComponent();
var localizationSettings = LocalizationSettings.GetInstance();
// Set Calendar Identifier
DateDiff_FromDate.CalendarIdentifier = localizationSettings.GetCalendarIdentifier();
DateDiff_ToDate.CalendarIdentifier = localizationSettings.GetCalendarIdentifier();
// Setting the FirstDayofWeek
DateDiff_FromDate.FirstDayOfWeek = localizationSettings.GetFirstDayOfWeek();
DateDiff_ToDate.FirstDayOfWeek = localizationSettings.GetFirstDayOfWeek();
// Setting the Language explicitly is not required,
// this is a workaround for the bug in the control due to which
// the displayed date is incorrect for non Gregorian Calendar Systems
// The displayed date doesn't honor the shortdate format, on setting the Language the format is refreshed
DateDiff_FromDate.Language = localizationSettings.GetLocaleName();
DateDiff_ToDate.Language = localizationSettings.GetLocaleName();
// Set Min and Max Dates according to the Gregorian Calendar(1601 & 9999)
var calendar = new Calendar();
var today = calendar.GetDateTime();
calendar.ChangeCalendarSystem(CalendarIdentifiers.Gregorian);
calendar.Day = 1;
calendar.Month = 1;
calendar.Year = c_minYear;
var minYear = calendar.GetDateTime(); // 1st January, 1601
DateDiff_FromDate.MinDate = minYear;
DateDiff_ToDate.MinDate = minYear;
calendar.Day = 31;
calendar.Month = 12;
calendar.Year = c_maxYear;
var maxYear = calendar.GetDateTime(); // 31st December, 9878
DateDiff_FromDate.MaxDate = maxYear;
DateDiff_ToDate.MaxDate = maxYear;
// Set the PlaceHolderText for CalendarDatePicker
DateTimeFormatter dateTimeFormatter = LocalizationService.GetRegionalSettingsAwareDateTimeFormatter(
"day month year",
localizationSettings.GetCalendarIdentifier(),
ClockIdentifiers.TwentyFourHour); // Clock Identifier is not used
DateDiff_FromDate.DateFormat = "day month year";
DateDiff_ToDate.DateFormat = "day month year";
var placeholderText = dateTimeFormatter.Format(today);
DateDiff_FromDate.PlaceholderText = placeholderText;
DateDiff_ToDate.PlaceholderText = placeholderText;
// TODO UNO
// CopyMenuItem.Text = AppResourceProvider.GetInstance().GetResourceString("copyMenuItem");
DateCalculationOption.SelectionChanged += new SelectionChangedEventHandler(DateCalcOption_Changed);
}
void FromDate_DateChanged( CalendarDatePicker sender, CalendarDatePickerDateChangedEventArgs e)
{
if (e.NewDate != null)
{
var dateCalcViewModel = (DateCalculatorViewModel)this.DataContext;
dateCalcViewModel.FromDate = e.NewDate.Value.DateTime;
TraceLogger.GetInstance().LogDateDifferenceModeUsed(ApplicationView.GetApplicationViewIdForWindow(CoreWindow.GetForCurrentThread()));
}
else
{
ReselectCalendarDate(sender, e.OldDate.Value.DateTime);
}
}
void ToDate_DateChanged( CalendarDatePicker sender, CalendarDatePickerDateChangedEventArgs e)
{
if (e.NewDate != null)
{
var dateCalcViewModel = (DateCalculatorViewModel)this.DataContext;
dateCalcViewModel.ToDate = e.NewDate.Value.DateTime;
TraceLogger.GetInstance().LogDateDifferenceModeUsed(ApplicationView.GetApplicationViewIdForWindow(CoreWindow.GetForCurrentThread()));
}
else
{
ReselectCalendarDate(sender, e.OldDate.Value.DateTime);
}
}
void AddSubtract_DateChanged( CalendarDatePicker sender, CalendarDatePickerDateChangedEventArgs e)
{
if (e.NewDate != null)
{
var dateCalcViewModel = (DateCalculatorViewModel)this.DataContext;
dateCalcViewModel.StartDate = e.NewDate.Value.DateTime;
TraceLogger.GetInstance().LogDateAddSubtractModeUsed(
ApplicationView.GetApplicationViewIdForWindow(CoreWindow.GetForCurrentThread()), dateCalcViewModel.IsAddMode);
}
else
{
ReselectCalendarDate(sender, e.OldDate.Value.DateTime);
}
}
void OffsetValue_Changed( object sender, SelectionChangedEventArgs e)
{
var dateCalcViewModel = (DateCalculatorViewModel)this.DataContext;
TraceLogger.GetInstance().LogDateAddSubtractModeUsed(
ApplicationView.GetApplicationViewIdForWindow(CoreWindow.GetForCurrentThread()), dateCalcViewModel.IsAddMode);
}
void OnCopyMenuItemClicked( object sender, RoutedEventArgs e)
{
// TODO UNO
//var calcResult = (TextBlock)ResultsContextMenu.Target;
//CopyPasteManager.CopyToClipboard(calcResult.Text);
}
void OnLoaded( object sender, Windows.UI.Xaml.RoutedEventArgs e)
{
}
public void CloseCalendarFlyout()
{
if (DateDiff_FromDate.IsCalendarOpen)
{
DateDiff_FromDate.IsCalendarOpen = false;
}
if (DateDiff_ToDate.IsCalendarOpen)
{
DateDiff_ToDate.IsCalendarOpen = false;
}
if ((AddSubtract_FromDate != null) && (AddSubtract_FromDate.IsCalendarOpen))
{
AddSubtract_FromDate.IsCalendarOpen = false;
}
}
public void SetDefaultFocus()
{
DateCalculationOption.Focus(FocusState.Programmatic);
}
void DateCalcOption_Changed( object sender, Windows.UI.Xaml.Controls.SelectionChangedEventArgs e)
{
FindName("AddSubtractDateGrid");
DateCalculationOption.SelectionChanged -= DateCalcOption_Changed;
}
void AddSubtractDateGrid_Loaded( object sender, Windows.UI.Xaml.RoutedEventArgs e)
{
var localizationSettings = LocalizationSettings.GetInstance();
AddSubtract_FromDate.PlaceholderText = DateDiff_FromDate.PlaceholderText;
AddSubtract_FromDate.CalendarIdentifier = localizationSettings.GetCalendarIdentifier();
AddSubtract_FromDate.FirstDayOfWeek = localizationSettings.GetFirstDayOfWeek();
AddSubtract_FromDate.Language = localizationSettings.GetLocaleName();
AddSubtract_FromDate.MinDate = DateDiff_FromDate.MinDate;
AddSubtract_FromDate.MaxDate = DateDiff_FromDate.MaxDate;
AddSubtract_FromDate.DateFormat = "day month year";
}
void ReselectCalendarDate( Windows.UI.Xaml.Controls.CalendarDatePicker calendarDatePicker, DateTime dateTime)
{
// Reselect the unselected Date
calendarDatePicker.Date = dateTime;
// Dismiss the Calendar flyout
calendarDatePicker.IsCalendarOpen = false;
}
void OffsetDropDownClosed( object sender, object e)
{
RaiseLiveRegionChangedAutomationEvent(/* DateDiff mode */ false);
}
void CalendarFlyoutClosed( object sender, object e)
{
var dateCalcViewModel = (DateCalculatorViewModel)this.DataContext;
RaiseLiveRegionChangedAutomationEvent(dateCalcViewModel.IsDateDiffMode);
}
void RaiseLiveRegionChangedAutomationEvent( bool isDateDiffMode)
{
TextBlock resultTextBlock = (isDateDiffMode ? DateDiffAllUnitsResultLabel : DateResultLabel);
String automationName = AutomationProperties.GetName(resultTextBlock);
TextBlockAutomationPeer.FromElement(resultTextBlock).RaiseAutomationEvent(AutomationEvents.LiveRegionChanged);
}
void AddSubtractOption_Checked( object sender, RoutedEventArgs e)
{
RaiseLiveRegionChangedAutomationEvent(/* DateDiff mode */ false);
}
}
}

View file

@ -284,19 +284,18 @@ namespace CalculatorApp
{
m_calculator.SetDefaultFocus();
}
if (m_dateCalculator != null && m_dateCalculator.Visibility == Visibility.Visible)
{
m_dateCalculator.SetDefaultFocus();
}
// UNO TODO
//if (m_converter != null && m_converter.Visibility == Visibility.Visible)
//{
// m_converter.SetDefaultFocus();
//}
}
// UNO TODO
//if (m_dateCalculator != null && m_dateCalculator.Visibility == Visibility.Visible)
//{
// m_dateCalculator.SetDefaultFocus();
//}
//if (m_converter != null && m_converter.Visibility == Visibility.Visible)
//{
// m_converter.SetDefaultFocus();
//}
}
void EnsureCalculator()
void EnsureCalculator()
{
if (m_calculator == null)
{
@ -336,23 +335,22 @@ namespace CalculatorApp
void EnsureDateCalculator()
{
// UNO TODO
//if (m_dateCalculator == null)
//{
// // delay loading converter
// m_dateCalculator = new DateCalculator();
// m_dateCalculator.Name = "dateCalculator";
// m_dateCalculator.DataContext = m_model.DateCalcViewModel;
if (m_dateCalculator == null)
{
// delay loading converter
m_dateCalculator = new DateCalculator();
m_dateCalculator.Name = "dateCalculator";
m_dateCalculator.DataContext = m_model.DateCalcViewModel;
// DateCalcHolder.Child = m_dateCalculator;
//}
DateCalcHolder.Child = m_dateCalculator;
}
//if (m_calculator != null)
//{
// m_calculator.CloseHistoryFlyout();
// m_calculator.CloseMemoryFlyout();
//}
}
if (m_calculator != null)
{
m_calculator.CloseHistoryFlyout();
m_calculator.CloseMemoryFlyout();
}
}
void EnsureConverter()
{