Merge pull request #5 from nventive/dev/dr/Date

Enable DateCalculator
This commit is contained in:
David 2019-05-22 11:24:45 -04:00 committed by GitHub
commit f93281dc78
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
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\CalculatorButtonUser.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Common\CalculatorDisplay.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Common\CalculatorDisplay.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Common\CopyPasteManager.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Common\CopyPasteManager.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Common\DateCalculator.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Common\DelegateCommand.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Common\DelegateCommand.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Common\DisplayExpressionToken.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Common\DisplayExpressionToken.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Common\EngineResourceProvider.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Common\EngineResourceProvider.cs" />
@ -48,6 +49,7 @@
<Compile Include="$(MSBuildThisFileDirectory)Common\MyVirtualKey.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Common\MyVirtualKey.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Common\NavCategory.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Common\NavCategory.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Common\TitleBarHelper.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Common\TitleBarHelper.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Common\TraceLogger.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Common\Utils.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Common\Utils.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Controls\CalculationResult.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Controls\CalculationResult.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Controls\CalculationResultAutomationPeer.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. // as configured by running intl.cpl.
// //
// This helper function creates a DateTimeFormatter with a TwentyFour hour clock // 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(); IEnumerable<String> languageIdentifiers = GetLanguageIdentifiers();
if (languageIdentifiers == null) if (languageIdentifiers == null)
@ -392,75 +392,39 @@ namespace CalculatorApp.Common
// If successful, returns a formatter that respects the user's regional format settings, // If successful, returns a formatter that respects the user's regional format settings,
// as configured by running intl.cpl. // 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 IEnumerable<string> languageIdentifiers = GetLanguageIdentifiers();
//IIterable<String> languageIdentifiers = GetLanguageIdentifiers(); if (languageIdentifiers == null)
//if (languageIdentifiers == null) {
//{ languageIdentifiers = ApplicationLanguages.Languages;
// languageIdentifiers = ApplicationLanguages.Languages; }
//}
//return new DateTimeFormatter(format, languageIdentifiers, GlobalizationPerences.HomeGeographicRegion, calendarIdentifier, clockIdentifier); return new DateTimeFormatter(format, languageIdentifiers, GlobalizationPreferences.HomeGeographicRegion, calendarIdentifier, clockIdentifier);
throw new NotImplementedException();
} }
public CurrencyFormatter GetRegionalSettingsAwareCurrencyFormatter() public static CurrencyFormatter GetRegionalSettingsAwareCurrencyFormatter()
{ {
// UNO TODO string userCurrency =
//string userCurrency = (GlobalizationPreferences.Currencies.Count > 0) ? GlobalizationPreferences.Currencies[0] : DefaultCurrencyCode;
// (GlobalizationPreferences.Currencies.Size > 0) ? GlobalizationPreferences.Currencies.GetAt(0) : string(DefaultCurrencyCode.data());
//IIterable<String> languageIdentifiers = GetLanguageIdentifiers(); IEnumerable<string> languageIdentifiers = GetLanguageIdentifiers();
//if (languageIdentifiers == null) if (languageIdentifiers == null)
//{ {
// languageIdentifiers = ApplicationLanguages.Languages; languageIdentifiers = ApplicationLanguages.Languages;
//} }
//var currencyFormatter = new CurrencyFormatter(userCurrency, languageIdentifiers, GlobalizationPerences.HomeGeographicRegion); var currencyFormatter = new CurrencyFormatter(userCurrency, languageIdentifiers, GlobalizationPreferences.HomeGeographicRegion);
//int fractionDigits = LocalizationSettings.GetInstance().GetCurrencyTrailingDigits(); int fractionDigits = LocalizationSettings.GetInstance().GetCurrencyTrailingDigits();
//currencyFormatter.FractionDigits = fractionDigits; currencyFormatter.FractionDigits = fractionDigits;
//return currencyFormatter; return currencyFormatter;
throw new NotImplementedException();
} }
static IEnumerable<String> GetLanguageIdentifiers() static IEnumerable<String> GetLanguageIdentifiers()
{ {
#if !HAS_UNO return GlobalizationPreferences.Languages;
//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
} }
// Resources for the engine use numbers as keys. It's inconvenient, but also difficult to // 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]; m_digitSymbols[i] = i.ToString(NumberFormatInfo.CurrentInfo)[0];
} }
// As CalcEngine only supports the first character of the decimal separator, // As CalcEngine only supports the first character of the decimal separator,
// Only first character of the decimal separator string is supported. // Only first character of the decimal separator string is supported.
m_decimalSeparator = NumberFormatInfo.CurrentInfo.NumberDecimalSeparator[0]; m_decimalSeparator = NumberFormatInfo.CurrentInfo.NumberDecimalSeparator[0];
m_numberGroupSeparator = NumberFormatInfo.CurrentInfo.NumberGroupSeparator[0]; m_numberGroupSeparator = NumberFormatInfo.CurrentInfo.NumberGroupSeparator[0];
m_numberGrouping = ""; // UNO TODO https://docs.microsoft.com/en-us/windows/desktop/Intl/locale-sgrouping m_numberGrouping = ""; // UNO TODO https://docs.microsoft.com/en-us/windows/desktop/Intl/locale-sgrouping
m_listSeparator = CultureInfo.CurrentCulture.TextInfo.ListSeparator; m_listSeparator = CultureInfo.CurrentCulture.TextInfo.ListSeparator;
m_currencyTrailingDigits = NumberFormatInfo.CurrentInfo.CurrencyDecimalDigits; m_currencyTrailingDigits = NumberFormatInfo.CurrentInfo.CurrencyDecimalDigits;
m_currencySymbolPrecedence = ~(NumberFormatInfo.CurrentInfo.CurrencyPositivePattern) & 1; m_currencySymbolPrecedence = ~(NumberFormatInfo.CurrentInfo.CurrencyPositivePattern) & 1;
m_resolvedName = CultureInfo.CurrentCulture.Name;
m_calendarIdentifier = "";//CultureInfo.CurrentCulture.DateTimeFormat.Calendar.ToString(); m_calendarIdentifier = new Windows.Globalization.Calendar().GetCalendarSystem();
m_firstDayOfWeek = (Windows.Globalization.DayOfWeek)CultureInfo.CurrentCulture.DateTimeFormat.FirstDayOfWeek; m_firstDayOfWeek = (Windows.Globalization.DayOfWeek)CultureInfo.CurrentCulture.DateTimeFormat.FirstDayOfWeek;
#endif #endif
} }
@ -155,7 +154,7 @@ namespace CalculatorApp
return m_localizationSettings; return m_localizationSettings;
} }
string GetLocaleName() public string GetLocaleName()
{ {
return m_resolvedName; return m_resolvedName;
} }
@ -326,7 +325,7 @@ namespace CalculatorApp
return m_listSeparator; return m_listSeparator;
} }
Windows.Globalization.DayOfWeek GetFirstDayOfWeek() public Windows.Globalization.DayOfWeek GetFirstDayOfWeek()
{ {
return m_firstDayOfWeek; 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; private StandardCalculatorViewModel m_CalculatorViewModel;
public StandardCalculatorViewModel CalculatorViewModel { get => m_CalculatorViewModel; set { m_CalculatorViewModel = value; RaisePropertyChanged("CalculatorViewModel"); } } public StandardCalculatorViewModel CalculatorViewModel { get => m_CalculatorViewModel; set { m_CalculatorViewModel = value; RaisePropertyChanged("CalculatorViewModel"); } }
// UNO TODO private DateCalculatorViewModel m_DateCalcViewModel;
//private DateCalculatorViewModel m_DateCalcViewModel; public DateCalculatorViewModel DateCalcViewModel { get => m_DateCalcViewModel; set { m_DateCalcViewModel = value; RaisePropertyChanged("DateCalcViewModel"); } }
//public DateCalculatorViewModel DateCalcViewModel { get => m_DateCalcViewModel; set { m_DateCalcViewModel = value; RaisePropertyChanged("DateCalcViewModel"); } }
// UNO TODO // UNO TODO
@ -160,12 +159,11 @@ namespace CalculatorApp.ViewModel
else if (NavCategory.IsDateCalculatorViewMode(m_mode)) else if (NavCategory.IsDateCalculatorViewMode(m_mode))
{ {
// TraceLogger.GetInstance().LogDateCalculatorModeViewed(m_mode, ApplicationView.GetApplicationViewIdForWindow(CoreWindow.GetForCurrentThread())); // TraceLogger.GetInstance().LogDateCalculatorModeViewed(m_mode, ApplicationView.GetApplicationViewIdForWindow(CoreWindow.GetForCurrentThread()));
// UNO TODO if (m_DateCalcViewModel == null)
//if (m_DateCalcViewModel == null) {
//{ m_DateCalcViewModel = new DateCalculatorViewModel();
// m_DateCalcViewModel = new DateCalculatorViewModel(); }
//} }
}
else if (NavCategory.IsConverterViewMode(m_mode)) else if (NavCategory.IsConverterViewMode(m_mode))
{ {
// UNO TODO // UNO TODO
@ -200,12 +198,13 @@ namespace CalculatorApp.ViewModel
//{ //{
// ConverterViewModel.OnCopyCommand(parameter); // ConverterViewModel.OnCopyCommand(parameter);
//} //}
//else if (NavCategory.IsDateCalculatorViewMode(m_mode))
//{
// DateCalcViewModel.OnCopyCommand(parameter);
//}
//else //else
{ if (NavCategory.IsDateCalculatorViewMode(m_mode))
{
DateCalcViewModel.OnCopyCommand(parameter);
}
else
{
CalculatorViewModel.OnCopyCommand(parameter); CalculatorViewModel.OnCopyCommand(parameter);
} }
} }

File diff suppressed because it is too large Load diff

View file

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

View file

@ -5,11 +5,10 @@
xmlns:converters="using:CalculatorApp.Converters" xmlns:converters="using:CalculatorApp.Converters"
xmlns:local="using:CalculatorApp.Views" xmlns:local="using:CalculatorApp.Views"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Loaded="OnLoaded"
mc:Ignorable=""> mc:Ignorable="">
<!-- UNO TODO Loaded="OnLoaded"--> <UserControl.Resources>
<!-- UNO TODO <UserControl.Resources>
<converters:BooleanNegationConverter x:Key="BooleanNegationConverter" /> <converters:BooleanNegationConverter x:Key="BooleanNegationConverter" />
<converters:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" /> <converters:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
<converters:BooleanToVisibilityNegationConverter x:Key="BooleanToVisibilityNegationConverter" /> <converters:BooleanToVisibilityNegationConverter x:Key="BooleanToVisibilityNegationConverter" />
@ -441,13 +440,13 @@
Value="False" /> Value="False" />
</Style> </Style>
<MenuFlyout x:Key="ResultsContextMenu" <!--TODO UNO <MenuFlyout x:Key="ResultsContextMenu"
x:Name="ResultsContextMenu"> x:Name="ResultsContextMenu">
<MenuFlyoutItem x:Name="CopyMenuItem" <MenuFlyoutItem x:Name="CopyMenuItem"
x:Uid="CopyMenuItem" x:Uid="CopyMenuItem"
Click="OnCopyMenuItemClicked" Click="OnCopyMenuItemClicked"
Icon="Copy" /> Icon="Copy" />
</MenuFlyout> </MenuFlyout>-->
</UserControl.Resources> </UserControl.Resources>
<Grid x:Name="DateCalculatorGrid" <Grid x:Name="DateCalculatorGrid"
@ -500,7 +499,7 @@
</VisualStateGroup> </VisualStateGroup>
</VisualStateManager.VisualStateGroups> </VisualStateManager.VisualStateGroups>
--><!-- ComboBox for Date Calculation options --><!-- <!-- ComboBox for Date Calculation options -->
<ComboBox x:Name="DateCalculationOption" <ComboBox x:Name="DateCalculationOption"
x:Uid="DateCalculationOption" x:Uid="DateCalculationOption"
Grid.Row="1" Grid.Row="1"
@ -518,7 +517,7 @@
IsSelected="{Binding IsDateDiffMode, Converter={StaticResource BooleanNegationConverter}, Mode=TwoWay}" /> IsSelected="{Binding IsDateDiffMode, Converter={StaticResource BooleanNegationConverter}, Mode=TwoWay}" />
</ComboBox> </ComboBox>
--><!-- Grid to Calculate Difference between Two Dates --><!-- <!-- Grid to Calculate Difference between Two Dates -->
<Grid x:Name="DateDiffGrid" <Grid x:Name="DateDiffGrid"
Grid.Row="2" Grid.Row="2"
Visibility="{Binding IsDateDiffMode, Converter={StaticResource BooleanToVisibilityConverter}}"> Visibility="{Binding IsDateDiffMode, Converter={StaticResource BooleanToVisibilityConverter}}">
@ -543,7 +542,7 @@
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
--><!-- From Date --><!-- <!-- From Date -->
<TextBlock x:Name="Date_FromLabel" <TextBlock x:Name="Date_FromLabel"
x:Uid="Date_FromLabel" x:Uid="Date_FromLabel"
Grid.Row="1" Grid.Row="1"
@ -559,7 +558,7 @@
Closed="CalendarFlyoutClosed" Closed="CalendarFlyoutClosed"
DateChanged="FromDate_DateChanged" /> DateChanged="FromDate_DateChanged" />
--><!-- To Date --><!-- <!-- To Date -->
<TextBlock x:Name="Date_ToLabel" <TextBlock x:Name="Date_ToLabel"
x:Uid="Date_ToLabel" x:Uid="Date_ToLabel"
Grid.Row="4" Grid.Row="4"
@ -576,7 +575,7 @@
Closed="CalendarFlyoutClosed" Closed="CalendarFlyoutClosed"
DateChanged="ToDate_DateChanged" /> DateChanged="ToDate_DateChanged" />
--><!-- Difference Result --><!-- <!-- Difference Result -->
<TextBlock x:Uid="Date_DifferenceLabel" <TextBlock x:Uid="Date_DifferenceLabel"
Grid.Row="7" Grid.Row="7"
Margin="0,0,0,0" Margin="0,0,0,0"
@ -599,7 +598,7 @@
Visibility="{Binding IsDiffInDays, Converter={StaticResource BooleanToVisibilityNegationConverter}}" /> Visibility="{Binding IsDiffInDays, Converter={StaticResource BooleanToVisibilityNegationConverter}}" />
</Grid> </Grid>
--><!-- Grid for Add/Subtract Date --><!-- <!-- Grid for Add/Subtract Date -->
<Grid x:Name="AddSubtractDateGrid" <Grid x:Name="AddSubtractDateGrid"
Grid.Row="2" Grid.Row="2"
x:DeferLoadStrategy="Lazy" x:DeferLoadStrategy="Lazy"
@ -624,7 +623,8 @@
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
--><!-- From Date --><!-- <!-- From Date -->
<TextBlock x:Name="AddSubtract_Date_FromLabel" <TextBlock x:Name="AddSubtract_Date_FromLabel"
x:Uid="Date_FromLabel" x:Uid="Date_FromLabel"
Grid.Row="1" Grid.Row="1"
@ -668,7 +668,8 @@
</Grid> </Grid>
--><!-- Date Offset to be Added/Subtracted --><!-- <!-- Date Offset to be Added/Subtracted -->
<Grid x:Name="DateOffsetGrid" <Grid x:Name="DateOffsetGrid"
Grid.Row="6"> Grid.Row="6">
@ -734,7 +735,8 @@
SelectionChanged="OffsetValue_Changed" /> SelectionChanged="OffsetValue_Changed" />
</Grid> </Grid>
--><!-- Resulting Date --><!-- <!-- Resulting Date -->
<TextBlock x:Uid="DateLabel" <TextBlock x:Uid="DateLabel"
Grid.Row="8" Grid.Row="8"
Foreground="{ThemeResource SystemControlPageTextBaseMediumBrush}" /> Foreground="{ThemeResource SystemControlPageTextBaseMediumBrush}" />
@ -748,5 +750,5 @@
ContextFlyout="{StaticResource ResultsContextMenu}" ContextFlyout="{StaticResource ResultsContextMenu}"
Text="{Binding StrDateResult}" /> Text="{Binding StrDateResult}" />
</Grid> </Grid>
</Grid>--> </Grid>
</UserControl> </UserControl>

View file

@ -1,17 +1,19 @@
using System; // Copyright (c) Microsoft Corporation. All rights reserved.
using System.Collections.Generic; // Licensed under the MIT License.
using System.IO;
using System;
using System.Linq; using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime; using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation; using Windows.Globalization;
using Windows.Foundation.Collections; using Windows.Globalization.DateTimeFormatting;
using Windows.UI.Core;
using Windows.UI.ViewManagement;
using Windows.UI.Xaml; 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;
using Windows.UI.Xaml.Controls.Primitives; using CalculatorApp.Common;
using Windows.UI.Xaml.Data; using CalculatorApp.ViewModel;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
// The User Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234236 // 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 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() public DateCalculator()
{ {
this.InitializeComponent(); 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(); 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 void EnsureCalculator()
//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()
{ {
if (m_calculator == null) if (m_calculator == null)
{ {
@ -336,23 +335,22 @@ namespace CalculatorApp
void EnsureDateCalculator() void EnsureDateCalculator()
{ {
// UNO TODO if (m_dateCalculator == null)
//if (m_dateCalculator == null) {
//{ // delay loading converter
// // delay loading converter m_dateCalculator = new DateCalculator();
// m_dateCalculator = new DateCalculator(); m_dateCalculator.Name = "dateCalculator";
// m_dateCalculator.Name = "dateCalculator"; m_dateCalculator.DataContext = m_model.DateCalcViewModel;
// m_dateCalculator.DataContext = m_model.DateCalcViewModel;
// DateCalcHolder.Child = m_dateCalculator; DateCalcHolder.Child = m_dateCalculator;
//} }
//if (m_calculator != null) if (m_calculator != null)
//{ {
// m_calculator.CloseHistoryFlyout(); m_calculator.CloseHistoryFlyout();
// m_calculator.CloseMemoryFlyout(); m_calculator.CloseMemoryFlyout();
//} }
} }
void EnsureConverter() void EnsureConverter()
{ {