Merged PR 9118731: Sync up to GitHub Repo main branch

Sync up to GitHub Repo main branch
This commit is contained in:
Han Zhang 👾 2023-06-12 05:39:09 +00:00
commit 4103f51be4
461 changed files with 29437 additions and 26432 deletions

View file

@ -8,7 +8,7 @@ assignees: ''
---
<!--
See https://github.com/Microsoft/calculator/blob/master/docs/NewFeatureProcess.md for suggestions on how to write a good feature pitch. Just want to submit an idea quickly? Try Feedback Hub instead: https://insider.windows.com/en-us/fb/?contextid=130
See https://github.com/Microsoft/calculator/blob/main/docs/NewFeatureProcess.md for suggestions on how to write a good feature pitch. Just want to submit an idea quickly? Try Feedback Hub instead: https://insider.windows.com/en-us/fb/?contextid=130
-->
**Problem Statement**

1550
.github/fabricbot.json vendored Normal file

File diff suppressed because it is too large Load diff

View file

@ -7,7 +7,7 @@
-
### How changes were validated:
<!--Review https://github.com/Microsoft/calculator/blob/master/CONTRIBUTING.md and ensure all contributing requirements are met.
<!--Review https://github.com/Microsoft/calculator/blob/main/CONTRIBUTING.md and ensure all contributing requirements are met.
Specify how you tested your changes (i.e. manual/ad-hoc testing, automated testing, new automated tests added)-->
-

3
.gitignore vendored
View file

@ -93,6 +93,9 @@ ipch/
*.vspx
*.sap
# Visual Studio Code
.vscode/
# TFS 2012 Local Workspace
$tf/

View file

@ -70,7 +70,7 @@ should be used where automated testing is not feasible.
### Git workflow
Calculator uses the [GitHub flow](https://guides.github.com/introduction/flow/) where most
development happens directly on the `master` branch. The `master` branch should always be in a
development happens directly on the `main` branch. The `main` branch should always be in a
healthy state which is ready for release.
If your change is complex, please clean up the branch history before submitting a pull request.

View file

@ -37,211 +37,3 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
---
Appium DotNet Driver
Copyright 2014-2015 Appium Contributors
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View file

@ -1,10 +1,10 @@
# Calculator
The Windows Calculator app is a modern Windows app written in C++ that ships pre-installed with Windows.
The Windows Calculator app is a modern Windows app written in C++ and C# that ships pre-installed with Windows.
The app provides standard, scientific, and programmer calculator functionality, as well as a set of converters between various units of measurement and currencies.
Calculator ships regularly with new features and bug fixes. You can get the latest version of Calculator in the [Microsoft Store](https://www.microsoft.com/store/apps/9WZDNCRFHVN5).
[![Build Status](https://dev.azure.com/ms/calculator/_apis/build/status/Calculator-CI?branchName=master)](https://dev.azure.com/ms/calculator/_build/latest?definitionId=57&branchName=master)
[![Build Status](https://dev.azure.com/ms/calculator/_apis/build/status/Calculator-CI?branchName=main)](https://dev.azure.com/ms/calculator/_build/latest?definitionId=57&branchName=main)
![Calculator Screenshot](docs/Images/CalculatorScreenshot.png)
@ -22,11 +22,11 @@ Calculator ships regularly with new features and bug fixes. You can get the late
## Getting started
Prerequisites:
- Your computer must be running Windows 10, version 1803 or newer.
- Your computer must be running Windows 11, build 22000 or newer.
- Install the latest version of [Visual Studio](https://developer.microsoft.com/en-us/windows/downloads) (the free community edition is sufficient).
- Install the "Universal Windows Platform Development" workload.
- Install the optional "C++ Universal Windows Platform tools" component.
- Install the latest Windows 10 SDK.
- Install the latest Windows 11 SDK.
![Visual Studio Installation Screenshot](docs/Images/VSInstallationScreenshot.png)
- Install the [XAML Styler](https://marketplace.visualstudio.com/items?itemName=TeamXavalon.XAMLStyler) Visual Studio extension.

View file

@ -0,0 +1,58 @@
#
# Continuous Integration (CI) - Internal
# This pipeline builds and validate the app for all supported architectures, in a production
# configuration. This pipeline relies on Microsoft-internal resources to run.
#
trigger:
- main
- release/*
- feature/*
pr: none
name: 0.$(Date:yyMM).$(DayOfMonth)$(Rev:rr).0
jobs:
- template: ./templates/build-single-architecture.yaml
parameters:
isReleaseBuild: true
useReleaseAppxManifest: false
platform: x64
- template: ./templates/build-single-architecture.yaml
parameters:
isReleaseBuild: true
useReleaseAppxManifest: false
platform: x86
- template: ./templates/build-single-architecture.yaml
parameters:
isReleaseBuild: true
useReleaseAppxManifest: false
platform: ARM
- template: ./templates/build-single-architecture.yaml
parameters:
isReleaseBuild: true
useReleaseAppxManifest: false
platform: ARM64
- template: ./templates/run-ui-tests.yaml
parameters:
platform: x64
runsettingsFileName: CalculatorUITests.ci-internal.runsettings
- template: ./templates/run-ui-tests.yaml
parameters:
platform: x86
runsettingsFileName: CalculatorUITests.ci-internal.runsettings
- template: ./templates/run-unit-tests.yaml
parameters:
platform: x64
- template: ./templates/run-unit-tests.yaml
parameters:
platform: x86
- template: ./templates/package-msixbundle.yaml

View file

@ -1,51 +1,60 @@
#
# Continuous Integration (CI)
# This pipeline builds and validate the app in all supported configurations. If the build was
# queued to validate a pull request, we build and test only x64.
# This pipeline builds and validate the app for all supported architectures, in a public
# configuration. If the build was queued to validate a pull request, we build and test only x64.
#
trigger:
- master
- main
- release/*
- feature/*
pr:
- master
- main
- release/*
- feature/*
name: 0.$(Date:yyMM).$(DayOfMonth)$(Rev:rr).0
jobs:
- template: ./templates/build-app-public.yaml
- template: ./templates/build-single-architecture.yaml
parameters:
platform: x64
isOSSBuild: true
- template: ./templates/build-app-public.yaml
- template: ./templates/build-single-architecture.yaml
parameters:
platform: x86
isOSSBuild: true
condition: not(eq(variables['Build.Reason'], 'PullRequest'))
- template: ./templates/build-app-public.yaml
- template: ./templates/build-single-architecture.yaml
parameters:
platform: ARM
isOSSBuild: true
condition: not(eq(variables['Build.Reason'], 'PullRequest'))
- template: ./templates/build-app-public.yaml
- template: ./templates/build-single-architecture.yaml
parameters:
platform: ARM64
isOSSBuild: true
condition: not(eq(variables['Build.Reason'], 'PullRequest'))
- template: ./templates/run-ui-tests.yaml
parameters:
platform: x64
isOSSBuild: true
runsettingsFileName: CalculatorUITests.ci.runsettings
- template: ./templates/run-unit-tests.yaml
parameters:
platform: x64
isOSSBuild: true
- template: ./templates/run-unit-tests.yaml
parameters:
platform: x86
isOSSBuild: true
- template: ./templates/package-appxbundle.yaml
- template: ./templates/package-msixbundle.yaml
parameters:
isOSSBuild: true

View file

@ -12,7 +12,7 @@ schedules:
displayName: Daily sync
branches:
include:
- master
- main
always: true
trigger: none
@ -23,7 +23,7 @@ name: $(BuildDefinitionName)_$(date:yyMM).$(date:dd)$(rev:rrr)
jobs:
- job: Localize
pool:
vmImage: windows-2019
name: EssentialExperiences-windows-2022
variables:
skipComponentGovernanceDetection: true
steps:
@ -51,4 +51,4 @@ jobs:
condition: eq(variables['hasChanges'], '1')
inputs:
artifactName: Patch
targetPath: $(Build.ArtifactStagingDirectory)
targetPath: $(Build.ArtifactStagingDirectory)

View file

@ -4,37 +4,43 @@
# Store and the Windows image. This pipeline relies on Microsoft-internal resources to run.
#
schedules:
- cron: "0 7 * * *"
displayName: Daily midnight build
branches:
include:
- master
trigger: none
pr: none
variables:
versionMajor: 10
versionMinor: 2103
versionBuild: $[counter('10.2103.*', 0)]
versionMajor: 11
versionMinor: 2305
versionBuild: $[counter(format('{0}.{1}.*', variables['versionMajor'], variables['versionMinor']), 0)]
versionPatch: 0
name: '$(versionMajor).$(versionMinor).$(versionBuild).$(versionPatch)'
jobs:
- template: ./templates/build-app-internal.yaml
- template: ./templates/build-single-architecture.yaml
parameters:
platform: x64
isReleaseBuild: true
useReleaseAppxmanifest: true
- template: ./templates/build-app-internal.yaml
- template: ./templates/build-single-architecture.yaml
parameters:
platform: x86
isReleaseBuild: true
useReleaseAppxmanifest: true
condition: not(eq(variables['Build.Reason'], 'PullRequest'))
- template: ./templates/build-app-internal.yaml
- template: ./templates/build-single-architecture.yaml
parameters:
platform: ARM
isReleaseBuild: true
useReleaseAppxmanifest: true
condition: not(eq(variables['Build.Reason'], 'PullRequest'))
- template: ./templates/build-single-architecture.yaml
parameters:
platform: ARM64
isReleaseBuild: true
useReleaseAppxmanifest: true
condition: not(eq(variables['Build.Reason'], 'PullRequest'))
- template: ./templates/run-ui-tests.yaml
@ -55,8 +61,10 @@ jobs:
parameters:
platform: x86
- template: ./templates/package-appxbundle.yaml
- template: ./templates/package-msixbundle.yaml
parameters:
signBundle: true
createStoreBrokerPackages: true
- template: ./templates/prepare-release-internalonly.yaml
- template: ./templates/release-store.yaml
- template: ./templates/release-vpack.yaml

View file

@ -1,65 +0,0 @@
# This template contains a job to build the app for a single architecture and run static analysis
# tools on the binaries.
# The app is built in a production configuration to be released to the Store and the Windows image.
# This job relies on Microsoft-internal resources to run.
parameters:
platform: ''
condition: ''
jobs:
- job: Build${{ parameters.platform }}
displayName: Build ${{ parameters.platform }}
condition: ${{ parameters.condition }}
pool:
vmImage: windows-2019
variables:
BuildConfiguration: Release
BuildPlatform: ${{ parameters.platform }}
steps:
- checkout: self
fetchDepth: 1
- task: UniversalPackages@0
displayName: Download internals package
inputs:
command: download
downloadDirectory: $(Build.SourcesDirectory)
vstsFeed: WindowsInboxApps
vstsFeedPackage: calculator-internals
vstsPackageVersion: 0.0.54
- template: ./build-single-architecture.yaml
parameters:
extraMsBuildArgs: '/p:IsStoreBuild=true'
- task: PublishSymbols@2
displayName: Publish symbols
inputs:
symbolsFolder: $(Build.BinariesDirectory)\$(BuildConfiguration)\$(BuildPlatform)
searchPattern: '**/*.pdb'
symbolServerType: teamServices
treatNotIndexedAsWarning: true
symbolsArtifactName: $(System.teamProject)/$(Build.BuildNumber)_$(BuildPlatform)$(BuildConfiguration)
- task: securedevelopmentteam.vss-secure-development-tools.build-task-binskim.BinSkim@3
displayName: Run BinSkim
inputs:
inputType: Basic
analyzeTarget: $(Build.BinariesDirectory)\$(BuildConfiguration)\$(BuildPlatform)\Calculator\*
analyzeVerbose: true
analyzeHashes: true
continueOnError: true
- task: securedevelopmentteam.vss-secure-development-tools.build-task-policheck.PoliCheck@1
displayName: Run PoliCheck
inputs:
targetType: F
- task: securedevelopmentteam.vss-secure-development-tools.build-task-publishsecurityanalysislogs.PublishSecurityAnalysisLogs@2
displayName: Publish security analysis logs
- task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0
displayName: Detect open source components
inputs:
sourceScanPath: $(Agent.BuildDirectory)

View file

@ -1,21 +0,0 @@
# This template contains a job to build the app for a single architecture.
# Only the contents of the public repository are built; internal resources are not used.
parameters:
platform: ''
condition: ''
jobs:
- job: Build${{ parameters.platform }}
displayName: Build ${{ parameters.platform }}
condition: ${{ parameters.condition }}
pool:
vmImage: windows-2019
variables:
BuildConfiguration: Release
BuildPlatform: ${{ parameters.platform }}
steps:
- checkout: self
fetchDepth: 1
- template: ./build-single-architecture.yaml

View file

@ -1,18 +1,58 @@
# This template contains steps to build the app for a single architecture.
# The job containing these steps must set the variables 'BuildConfiguration' and 'BuildPlatform'.
# This template contains a job to build the app for a single architecture.
parameters:
extraMsBuildArgs: ''
isReleaseBuild: false
isOSSBuild: false
useReleaseAppxManifest: false
platform: ''
condition: ''
jobs:
- job: Build${{ parameters.platform }}
displayName: Build ${{ parameters.platform }}
condition: ${{ parameters.condition }}
pool:
${{ if eq(parameters.isOSSBuild, true) }}:
name: EssentialExperiencesOpenSource-windows-2022
${{ if eq(parameters.isOSSBuild, false) }}:
name: EssentialExperiences-windows-2022
variables:
BuildConfiguration: Release
BuildPlatform: ${{ parameters.platform }}
${{ if eq(parameters.isReleaseBuild, true) }}:
${{ if eq(parameters.useReleaseAppxManifest, true) }}:
ExtraMSBuildArgs: '/p:IsStoreBuild=true /p:UseReleaseAppxManifest=true'
${{ if eq(parameters.useReleaseAppxManifest, false) }}:
ExtraMSBuildArgs: '/p:IsStoreBuild=true'
${{ if eq(parameters.isReleaseBuild, false) }}:
${{ if eq(parameters.useReleaseAppxManifest, true) }}:
ExtraMSBuildArgs: '/p:UseReleaseAppxManifest=true'
${{ if eq(parameters.useReleaseAppxManifest, false) }}:
ExtraMSBuildArgs: ''
${{ if eq(parameters.useReleaseAppxManifest, false) }}:
ManifestFileName: 'Package.appxmanifest'
${{ if eq(parameters.useReleaseAppxManifest, true) }}:
ManifestFileName: 'Package.Release.appxmanifest'
steps:
- checkout: self
fetchDepth: 1
- ${{ if eq(parameters.isReleaseBuild, true) }}:
- task: UniversalPackages@0
displayName: Download internals package
inputs:
command: download
downloadDirectory: $(Build.SourcesDirectory)
vstsFeed: WindowsInboxApps
vstsFeedPackage: calculator-internals
vstsPackageVersion: 0.0.105
steps:
- task: NuGetToolInstaller@1
displayName: Use NuGet 5.x
displayName: Use NuGet 6.x
inputs:
versionSpec: 5.x
versionSpec: 6.x
# In most accounts, you can just use 'NuGetCommand' instead of this GUID.
# In the microsoft.visualstudio.com account, NuGetCommand is ambiguous so the GUID is needed.
- task: 333b11bd-d341-40d9-afcf-b32d5ce6f23b@2
- task: NuGetCommand@2
displayName: NuGet restore src/Calculator.sln
inputs:
command: custom
@ -22,21 +62,82 @@ steps:
displayName: Set version number in AppxManifest
inputs:
filePath: $(Build.SourcesDirectory)\build\scripts\UpdateAppxManifestVersion.ps1
arguments: '-AppxManifest $(Build.SourcesDirectory)\src\Calculator\Package.appxmanifest -Version $(Build.BuildNumber)'
arguments: '-AppxManifest $(Build.SourcesDirectory)\src\Calculator\$(ManifestFileName) -Version $(Build.BuildNumber)'
- task: VSBuild@1
displayName: 'Build solution src/Calculator.sln'
inputs:
solution: src/Calculator.sln
vsVersion: 16.0
msbuildArgs: /bl:$(Build.BinariesDirectory)\$(BuildConfiguration)\$(BuildPlatform)\Calculator.binlog /p:OutDir=$(Build.BinariesDirectory)\$(BuildConfiguration)\$(BuildPlatform)\ /p:GenerateProjectSpecificOutputFolder=true /p:AppVersion=$(Build.BuildNumber) /t:Publish /p:PublishDir=$(Build.BinariesDirectory)\$(BuildConfiguration)\$(BuildPlatform)\publish\ ${{ parameters.extraMsBuildArgs }}
vsVersion: 17.0
msbuildArgs: /bl:$(Build.BinariesDirectory)\$(BuildConfiguration)\$(BuildPlatform)\Calculator.binlog /p:OutDir=$(Build.BinariesDirectory)\$(BuildConfiguration)\$(BuildPlatform)\ /p:GenerateProjectSpecificOutputFolder=true /p:Version=$(Build.BuildNumber) /t:Publish /p:PublishDir=$(Build.BinariesDirectory)\$(BuildConfiguration)\$(BuildPlatform)\publish\ $(ExtraMSBuildArgs)
platform: $(BuildPlatform)
configuration: $(BuildConfiguration)
maximumCpuCount: true
- ${{ if eq(parameters.isReleaseBuild, true) }}:
- task: AzureArtifacts.manifest-generator-task.manifest-generator-task.ManifestGeneratorTask@0
displayName: 'Generate Software Bill of Material(SBoM)'
inputs:
BuildDropPath: $(Build.BinariesDirectory)\$(BuildConfiguration)\$(BuildPlatform)\Calculator
PackageName: 'Microsoft.WindowsCalculator'
PackageVersion: $(Build.BuildNumber)
- task: PublishBuildArtifacts@1
displayName: Publish drop artifact
inputs:
artifactName: drop
pathToPublish: $(Build.BinariesDirectory)
parallel: true
- ${{ if eq(parameters.isReleaseBuild, true) }}:
- task: PublishSymbols@2
displayName: Publish symbols
inputs:
symbolsFolder: $(Build.BinariesDirectory)\$(BuildConfiguration)\$(BuildPlatform)
searchPattern: '**/*.pdb'
symbolServerType: teamServices
treatNotIndexedAsWarning: true
symbolsArtifactName: $(System.teamProject)/$(Build.BuildNumber)_$(BuildPlatform)$(BuildConfiguration)
- task: CopyFiles@2
displayName: Copy Files for BinSkim analysis
inputs:
SourceFolder: '$(Build.BinariesDirectory)\$(BuildConfiguration)\$(BuildPlatform)\Calculator\'
# Setting up a folder to store all the binary files that we need BinSkim to scan.
# If we put more things than we produce pdbs for and can index (such as nuget packages that ship without pdbs), binskim will fail.
# Below are ignored files
# - clrcompression.dll
# - WebView2Loader.dll
# - Microsoft.Web.WebView2.Core.dll
Contents: |
**\*
!**\clrcompression.dll
!**\WebView2Loader.dll
!**\Microsoft.Web.WebView2.Core.dll
TargetFolder: '$(Agent.BuildDirectory)\binskim'
CleanTargetFolder: true
OverWrite: true
flattenFolders: false
analyzeTarget: '$(Agent.BuildDirectory)\binskim\*'
- task: securedevelopmentteam.vss-secure-development-tools.build-task-binskim.BinSkim@3
displayName: Run BinSkim
inputs:
inputType: Basic
analyzeTarget: '$(Agent.BuildDirectory)\binskim\*'
analyzeVerbose: true
analyzeHashes: true
continueOnError: true
- task: securedevelopmentteam.vss-secure-development-tools.build-task-policheck.PoliCheck@1
displayName: Run PoliCheck
inputs:
targetType: F
- task: securedevelopmentteam.vss-secure-development-tools.build-task-publishsecurityanalysislogs.PublishSecurityAnalysisLogs@2
displayName: Publish security analysis logs
- task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0
displayName: Detect open source components
inputs:
sourceScanPath: $(Agent.BuildDirectory)

View file

@ -1,101 +0,0 @@
# This template contains a job which takes .appx packages which were built separately for each
# architecture (arm, x86, etc.) and combines them into a single .appxbundle.
parameters:
signBundle: false
jobs:
- job: Package
dependsOn:
- Buildx64
- Buildx86
- BuildARM
condition: |
and
(
in(dependencies.Buildx64.result, 'Succeeded', 'SucceededWithIssues', 'Skipped'),
in(dependencies.Buildx86.result, 'Succeeded', 'SucceededWithIssues', 'Skipped'),
in(dependencies.BuildARM.result, 'Succeeded', 'SucceededWithIssues', 'Skipped')
)
pool:
vmImage: windows-2019
variables:
skipComponentGovernanceDetection: true
steps:
- checkout: self
fetchDepth: 1
- task: DownloadBuildArtifacts@0
displayName: Download all .appx artifacts
inputs:
artifactName: drop
itemPattern: '**/*.appx'
- task: PowerShell@2
displayName: Generate AppxBundle mapping
inputs:
filePath: $(Build.SourcesDirectory)\build\scripts\CreateAppxBundleMapping.ps1
arguments: '-InputPath $(Build.ArtifactStagingDirectory)\drop\Release -ProjectName Calculator -OutputFile $(Build.BinariesDirectory)\AppxBundleMapping.txt'
- powershell: |
$buildVersion = [version]$Env:BUILDVERSION
$bundleVersion = "2020.$($buildVersion.Minor).$($buildVersion.Build).$($buildVersion.Revision)"
& "C:\Program Files (x86)\Windows Kits\10\bin\10.0.18362.0\x86\MakeAppx.exe" bundle /v /bv $bundleVersion /f $Env:MAPPINGFILEPATH /p $Env:OUTPUTPATH
displayName: Make AppxBundle
env:
BUILDVERSION: $(Build.BuildNumber)
MAPPINGFILEPATH: $(Build.BinariesDirectory)\AppxBundleMapping.txt
OUTPUTPATH: $(Build.BinariesDirectory)\Microsoft.WindowsCalculator_8wekyb3d8bbwe.appxbundle
- task: CopyFiles@2
displayName: Copy AppxBundle to staging directory
inputs:
sourceFolder: $(Build.BinariesDirectory)
contents: Microsoft.WindowsCalculator_8wekyb3d8bbwe.appxbundle
targetFolder: $(Build.ArtifactStagingDirectory)\appxBundle
- task: PublishBuildArtifacts@1
displayName: Publish AppxBundle artifact
inputs:
artifactName: appxBundle
pathToPublish: $(Build.ArtifactStagingDirectory)\appxBundle
- ${{ if eq(parameters.signBundle, true) }}:
- task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@1
displayName: Send appxbundle to code signing service
inputs:
ConnectedServiceName: Essential Experiences Codesign
FolderPath: $(Build.ArtifactStagingDirectory)\appxBundle
Pattern: Microsoft.WindowsCalculator_8wekyb3d8bbwe.appxbundle
signConfigType: inlineSignParams
inlineOperation: |
[
{
"CertTemplateName": "WINMSAPP1ST",
"CertSubjectName": "CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US",
"KeyCode": "Dynamic",
"OperationCode": "SigntoolvNextSign",
"Parameters": {
"OpusName": "Microsoft",
"OpusInfo": "http://www.microsoft.com",
"FileDigest": "/fd \"SHA256\"",
"TimeStamp": "/tr \"http://rfc3161.gtm.corp.microsoft.com/TSS/HttpTspServer\" /td sha256"
},
"ToolName": "sign",
"ToolVersion": "1.0"
},
{
"CertTemplateName": "WINMSAPP1ST",
"CertSubjectName": "CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US",
"KeyCode": "Dynamic",
"OperationCode": "SigntoolvNextVerify",
"Parameters": {},
"ToolName": "sign",
"ToolVersion": "1.0"
}
]
- task: PublishBuildArtifacts@1
displayName: Publish AppxBundleSigned artifact
inputs:
pathtoPublish: $(Build.ArtifactStagingDirectory)\appxBundle
artifactName: appxBundleSigned

View file

@ -0,0 +1,160 @@
# This template contains a job which takes .msix packages which were built separately for each
# architecture (arm, x86, etc.) and combines them into a single .msixbundle. In release builds,
# this job also signs the bundle and creates StoreBroker packages.
parameters:
isOSSBuild: false
signBundle: false
createStoreBrokerPackages: false
jobs:
- job: Package
dependsOn:
- Buildx64
- Buildx86
- BuildARM
- BuildARM64
condition: |
and
(
in(dependencies.Buildx64.result, 'Succeeded', 'SucceededWithIssues', 'Skipped'),
in(dependencies.Buildx86.result, 'Succeeded', 'SucceededWithIssues', 'Skipped'),
in(dependencies.BuildARM.result, 'Succeeded', 'SucceededWithIssues', 'Skipped'),
in(dependencies.BuildARM64.result, 'Succeeded', 'SucceededWithIssues', 'Skipped')
)
pool:
${{ if eq(parameters.isOSSBuild, true) }}:
name: EssentialExperiencesOpenSource-windows-2022
${{ if eq(parameters.isOSSBuild, false) }}:
name: EssentialExperiences-windows-2022
variables:
skipComponentGovernanceDetection: true
StoreBrokerMediaRootPath: $(TEMP)\SBMedia
StoreBrokerPackagePath: $(Build.ArtifactStagingDirectory)\storeBrokerPayload
steps:
- checkout: self
fetchDepth: 1
- task: DownloadBuildArtifacts@0
displayName: Download all .msix artifacts
inputs:
artifactName: drop
itemPattern: '**/*.msix'
- ${{ if eq(parameters.createStoreBrokerPackages, true) }}:
- task: UniversalPackages@0
displayName: Download internals package
inputs:
command: download
downloadDirectory: $(Build.SourcesDirectory)
vstsFeed: WindowsInboxApps
vstsFeedPackage: calculator-internals
vstsPackageVersion: 0.0.105
- task: PowerShell@2
displayName: Generate MsixBundle mapping
inputs:
filePath: $(Build.SourcesDirectory)\build\scripts\CreateMsixBundleMapping.ps1
arguments: '-InputPath $(Build.ArtifactStagingDirectory)\drop\Release -ProjectName Calculator -OutputFile $(Build.BinariesDirectory)\MsixBundleMapping.txt'
- powershell: |
$buildVersion = [version]$Env:BUILDVERSION
$bundleVersion = "2021.$($buildVersion.Minor).$($buildVersion.Build).$($buildVersion.Revision)"
& "C:\Program Files (x86)\Windows Kits\10\bin\10.0.22000.0\x64\MakeAppx.exe" bundle /v /bv $bundleVersion /f $Env:MAPPINGFILEPATH /p $Env:OUTPUTPATH
displayName: Make MsixBundle
env:
BUILDVERSION: $(Build.BuildNumber)
MAPPINGFILEPATH: $(Build.BinariesDirectory)\MsixBundleMapping.txt
OUTPUTPATH: $(Build.BinariesDirectory)\Microsoft.WindowsCalculator_8wekyb3d8bbwe.msixbundle
- task: CopyFiles@2
displayName: Copy MsixBundle to staging directory
inputs:
sourceFolder: $(Build.BinariesDirectory)
contents: Microsoft.WindowsCalculator_8wekyb3d8bbwe.msixbundle
targetFolder: $(Build.ArtifactStagingDirectory)\msixBundle
- task: PublishBuildArtifacts@1
displayName: Publish MsixBundle artifact
inputs:
artifactName: msixBundle
pathToPublish: $(Build.ArtifactStagingDirectory)\msixBundle
- ${{ if eq(parameters.signBundle, true) }}:
- task: EsrpCodeSigning@2
displayName: Send msixbundle to code signing service
inputs:
ConnectedServiceName: Essential Experiences Codesign
FolderPath: $(Build.ArtifactStagingDirectory)\msixBundle
Pattern: Microsoft.WindowsCalculator_8wekyb3d8bbwe.msixbundle
signConfigType: inlineSignParams
inlineOperation: |
[
{
"CertTemplateName": "WINMSAPP1ST",
"CertSubjectName": "CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US",
"KeyCode": "Dynamic",
"OperationCode": "SigntoolvNextSign",
"Parameters": {
"OpusName": "Microsoft",
"OpusInfo": "http://www.microsoft.com",
"FileDigest": "/fd \"SHA256\"",
"TimeStamp": "/tr \"http://rfc3161.gtm.corp.microsoft.com/TSS/HttpTspServer\" /td sha256"
},
"ToolName": "sign",
"ToolVersion": "1.0"
},
{
"CertTemplateName": "WINMSAPP1ST",
"CertSubjectName": "CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US",
"KeyCode": "Dynamic",
"OperationCode": "SigntoolvNextVerify",
"Parameters": {},
"ToolName": "sign",
"ToolVersion": "1.0"
}
]
- task: PublishBuildArtifacts@1
displayName: Publish MsixBundleSigned artifact
inputs:
pathtoPublish: $(Build.ArtifactStagingDirectory)\msixBundle
artifactName: msixBundleSigned
- ${{ if eq(parameters.createStoreBrokerPackages, true) }}:
- powershell: |
# Just modify this line to indicate where your en-us PDP file is. Leave the other lines alone.
$enUSPdpFilePath = "$(Build.SourcesDirectory)\PDP\en-US\PDP.xml"
# This is going to save the release value from the PDP file to $(SBMediaReleaseVersion)
# which you can then refer to in the UniversalPackages task.
$release = ([xml](Get-Content $enUSPdpFilePath)).ProductDescription.Release.Trim()
Write-Host "##vso[task.setvariable variable=SBMediaReleaseVersion;]$release"
displayName: Determine the PDP Media release version from the en-us PDP file
- task: UniversalPackages@0
displayName: Download PDP media (screenshots, trailers) universal package
inputs:
command: download
downloadDirectory: $(StoreBrokerMediaRootPath)/$(SBMediaReleaseVersion)
vstsFeed: WindowsInboxApps
vstsFeedPackage: calculator-pdp-media
vstsPackageVersion: $(SBMediaReleaseVersion)
- task: MS-RDX-MRO.windows-store-publish-dev.package-task.store-package@2
displayName: Create StoreBroker Payload
inputs:
serviceEndpoint: Calculator StoreBroker Connection
sbConfigPath: Tools/Build/StoreBroker/SBCalculatorConfig.json
sourceFolder: $(Build.ArtifactStagingDirectory)/msixBundle
contents: Microsoft.WindowsCalculator_8wekyb3d8bbwe.msixbundle
pdpPath: $(Build.SourcesDirectory)\PDP
pdpInclude: PDP.xml
pdpMediaPath: $(StoreBrokerMediaRootPath)
outSBPackagePath: $(StoreBrokerPackagePath)
outSBName: SBCalculator
- task: PublishBuildArtifacts@1
displayName: Publish StoreBroker Payload artifact
inputs:
pathtoPublish: $(StoreBrokerPackagePath)
artifactName: storeBrokerPayload

View file

@ -1,156 +0,0 @@
# This template contains a job which builds artifacts needed to release the app to the store and to
# Windows using Microsoft-internal systems. It relies on Microsoft-internal resources and will not
# work outside of Microsoft.
# Specifically, this job:
# - Builds VPacks for including the app in the Windows OS build. Azure DevOps Universal Packages
# offers similar capabilities.
# - Creates StoreBroker packages containing Microsoft Store assets. Although the Store assets for
# this app are not open source, the StoreBroker tool is available at
# https://github.com/Microsoft/StoreBroker.
jobs:
- job: WindowsInternalRelease
dependsOn: Package
pool:
name: Package ES Standard Build
workspace:
clean: outputs
variables:
skipComponentGovernanceDetection: true
SBMediaRootPath: '$(TEMP)\SBMedia'
SBPackagePath: '$(Build.ArtifactStagingDirectory)\storeBrokerPayload'
SBLogPath: '$(SBPackagePath)\StoreBroker.log'
FlightId: '161f0975-cb5f-475b-8ef6-26383c37621f'
AppId: '9WZDNCRFHVN5'
ProductId: '00009007199266248474'
steps:
- checkout: self
clean: true
# This must be the first task in the job definition, since it modifies the build environment
# in ways other tasks would not expect (for example, it clears the artifacts directory).
- task: PkgESSetupBuild@10
displayName: Initialize Package ES
inputs:
productName: Calculator
disableWorkspace: true
useDfs: false
env:
XES_DISABLEPROV: true
- task: NuGetToolInstaller@1
displayName: Use NuGet 5.x
inputs:
versionSpec: 5.x
- task: DownloadBuildArtifacts@0
displayName: Download appxBundleSigned artifact
inputs:
artifactName: appxBundleSigned
- task: CopyFiles@2
displayName: Copy signed AppxBundle to vpack staging folder
inputs:
sourceFolder: $(Build.ArtifactStagingDirectory)\appxBundleSigned
contents: Microsoft.WindowsCalculator_8wekyb3d8bbwe.appxbundle
targetFolder: $(Build.ArtifactStagingDirectory)\vpack\appxBundle
- task: PkgESVPack@10
displayName: Create and push vpack for app
env:
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
inputs:
sourceDirectory: $(Build.ArtifactStagingDirectory)\vpack\appxBundle
description: VPack for the Calculator Application
pushPkgName: calculator.app
version: $(versionMajor).$(versionMinor).$(versionBuild)
owner: paxeeapps
provData: false
- task: PublishBuildArtifacts@1
displayName: Publish vpack\app artifact with vpack manifest
inputs:
pathtoPublish: $(XES_VPACKMANIFESTDIRECTORY)\$(XES_VPACKMANIFESTNAME)
artifactName: vpack\app
- task: UniversalPackages@0
displayName: Download internals package
inputs:
command: download
downloadDirectory: $(Build.SourcesDirectory)
vstsFeed: WindowsInboxApps
vstsFeedPackage: calculator-internals
vstsPackageVersion: 0.0.54
- powershell: |
# Just modify this line to indicate where your en-us PDP file is. Leave the other lines alone.
$enUSPdpFilePath = "$(Build.SourcesDirectory)\PDP\en-US\PDP.xml"
# This is going to save the release value from the PDP file to $(SBMediaReleaseVersion)
# which you can then refer to in the UniversalPackages task.
$release = ([xml](Get-Content $enUSPdpFilePath)).ProductDescription.Release.Trim()
Write-Host "##vso[task.setvariable variable=SBMediaReleaseVersion;]$release"
displayName: Determine the PDP Media release version from the en-us PDP file
- task: UniversalPackages@0
displayName: Download PDP media (screenshots, trailers) universal package
inputs:
command: download
downloadDirectory: $(SBMediaRootPath)/$(SBMediaReleaseVersion)
vstsFeed: WindowsInboxApps
vstsFeedPackage: calculator-pdp-media
vstsPackageVersion: $(SBMediaReleaseVersion)
- task: MS-RDX-MRO.windows-store-publish-dev.package-task.store-package@2
displayName: Create StoreBroker Payload
inputs:
serviceEndpoint: Essential Experiences StoreBrokerProxy
sbConfigPath: Tools/Build/StoreBroker/SBCalculatorConfig.json
sourceFolder: $(Build.ArtifactStagingDirectory)/appxBundleSigned
contents: Microsoft.WindowsCalculator_8wekyb3d8bbwe.appxbundle
pdpPath: '$(Build.SourcesDirectory)\PDP'
pdpInclude: PDP.xml
pdpMediaPath: '$(SBMediaRootPath)'
outSBPackagePath: '$(SBPackagePath)'
outSBName: SBCalculator
- task: PublishBuildArtifacts@1
displayName: Publish StoreBroker Payload artifact
inputs:
pathtoPublish: '$(SBPackagePath)'
artifactName: storeBrokerPayload
- task: MS-RDX-MRO.windows-store-publish-dev.flight-task.store-flight@2
displayName: 'Flight StoreBroker Payload to team ring'
name: StoreBrokerFlight
inputs:
serviceEndpoint: Essential Experiences StoreBrokerProxy
appId: '$(AppId)'
flightId: '$(FlightId)'
inputMethod: JsonAndZip
jsonPath: '$(SBPackagePath)\SBCalculator.json'
zipPath: '$(SBPackagePath)\SBCalculator.zip'
force: true
skipPolling: true
targetPublishMode: Immediate
logPath: '$(SBLogPath)'
deletePackages: true
numberOfPackagesToKeep: 0
- task: PkgESStoreBrokerAeroUpload@10
displayName: Upload to Aero flighting dashboard
env:
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
inputs:
ProductId: '$(ProductId)'
FlightId: '$(FlightId)'
SubmissionId: '$(StoreBrokerFlight.WS_SubmissionId)'
SubmissionDataPath: '$(SBPackagePath)\SBCalculator.json'
PackagePath: '$(SBPackagePath)\SBCalculator.zip'
AeroEnvironment: Production
- task: PkgESLateTasks@10
displayName: Run PackageES LateTasks
env:
XES_DISABLEPROV: true

View file

@ -0,0 +1,48 @@
# This template contains jobs to release the app to the Store.
jobs:
- job: ReleaseStore
dependsOn: Package
pool:
name: EssentialExperiences-windows-2022
variables:
skipComponentGovernanceDetection: true
StoreBrokerPackagePath: $(Build.ArtifactStagingDirectory)\storeBrokerPayload
StoreBrokerLogPath: $(StoreBrokerPackagePath)\StoreBroker.log
FlightId: 161f0975-cb5f-475b-8ef6-26383c37621f
AppId: 9WZDNCRFHVN5
ProductId: 00009007199266248474
steps:
- checkout: none
- task: DownloadBuildArtifacts@0
displayName: Download storeBrokerPayload artifact
inputs:
artifactName: storeBrokerPayload
- task: MS-RDX-MRO.windows-store-publish-dev.flight-task.store-flight@2
displayName: Flight StoreBroker Payload to team ring
name: StoreBrokerFlight
inputs:
serviceEndpoint: Calculator StoreBroker Connection
appId: $(AppId)
flightId: $(FlightId)
inputMethod: JsonAndZip
jsonPath: $(StoreBrokerPackagePath)\SBCalculator.json
zipPath: $(StoreBrokerPackagePath)\SBCalculator.zip
force: true
skipPolling: true
targetPublishMode: Immediate
logPath: $(StoreBrokerLogPath)
deletePackages: true
numberOfPackagesToKeep: 0
- task: APS-Aero-Package.aero-upload-task.AeroUploadTask.AeroUpload@0
displayName: Aero Upload
inputs:
productId: $(ProductId)
flightId: $(FlightId)
submissionId: $(StoreBrokerFlight.WS_SubmissionId)
submissionDataPath: $(StoreBrokerPackagePath)\SBCalculator.json
packagePath: $(StoreBrokerPackagePath)\SBCalculator.zip
serviceEndpoint: AeroUpload-APS-Calculator

View file

@ -0,0 +1,42 @@
# This template contains a job to create a VPack. The VPack is used to preinstall the app in a
# Windows OS build.
jobs:
- job: ReleaseVPack
dependsOn: Package
pool:
name: EssentialExperiences-windows-2022
variables:
skipComponentGovernanceDetection: true
steps:
- checkout: none
- task: DownloadBuildArtifacts@0
displayName: Download msixBundleSigned artifact
inputs:
artifactName: msixBundleSigned
- task: CopyFiles@2
displayName: Copy signed MsixBundle to vpack staging folder
inputs:
sourceFolder: $(Build.ArtifactStagingDirectory)\msixBundleSigned
contents: Microsoft.WindowsCalculator_8wekyb3d8bbwe.msixbundle
targetFolder: $(Build.ArtifactStagingDirectory)\vpack\msixBundle
- task: PkgESVPack@12
displayName: Create and push vpack for app
env:
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
inputs:
sourceDirectory: $(Build.ArtifactStagingDirectory)\vpack\msixBundle
description: VPack for the Calculator Application
pushPkgName: calculator.app
version: $(versionMajor).$(versionMinor).$(versionBuild)
owner: paxeeapps
provData: true
- task: PublishBuildArtifacts@1
displayName: Publish vpack\app artifact with vpack manifest
inputs:
pathtoPublish: $(XES_VPACKMANIFESTDIRECTORY)\$(XES_VPACKMANIFESTNAME)
artifactName: vpackManifest

View file

@ -1,6 +1,7 @@
# This template contains jobs to run UI tests using WinAppDriver.
parameters:
isOSSBuild: false
platform: ''
runsettingsFileName: ''
@ -10,18 +11,30 @@ jobs:
dependsOn: Build${{ parameters.platform }}
condition: succeeded()
pool:
vmImage: windows-2019
${{ if eq(parameters.isOSSBuild, true) }}:
name: EssentialExperiencesOpenSource-Win11
${{ if eq(parameters.isOSSBuild, false) }}:
name: EssentialExperiences-Win11
variables:
skipComponentGovernanceDetection: true
steps:
- checkout: none
- checkout: self
fetchDepth: 1
- powershell: Set-DisplayResolution -Width 1920 -Height 1080 -Force
displayName: Set resolution to 1920x1080
continueOnError: true
- task: PowerShell@2
displayName: Turn off animation effects
inputs:
filePath: $(Build.SourcesDirectory)\build\scripts\TurnOffAnimationEffects.ps1
- task: ScreenResolutionUtility@1
displayName: Set resolution to 1920x1080
inputs:
displaySettings: 'specific'
width: 1920
height: 1080
- task: DownloadBuildArtifacts@0
displayName: Download AppxBundle and CalculatorUITests
displayName: Download MsixBundle and CalculatorUITests
inputs:
artifactName: drop
itemPattern: |
@ -44,9 +57,8 @@ jobs:
displayName: Run CalculatorUITests
inputs:
testAssemblyVer2: $(Build.ArtifactStagingDirectory)/drop/Release/${{ parameters.platform }}/publish/CalculatorUITests.dll
vsTestVersion: 16.0
runSettingsFile: $(Build.ArtifactStagingDirectory)/drop/Release/${{ parameters.platform }}/publish/${{ parameters.runsettingsFileName }}
platform: ${{ parameters.platform }}
configuration: Release
${{ if eq(variables['Build.Reason'], 'PullRequest') }}:
testFiltercriteria: Priority=0
testFiltercriteria: Priority=0

View file

@ -1,6 +1,7 @@
# This template contains jobs to run unit tests.
parameters:
isOSSBuild: false
platform: ''
runsettingsFileName: ''
@ -10,7 +11,10 @@ jobs:
dependsOn: Build${{ parameters.platform }}
condition: succeeded()
pool:
vmImage: windows-2019
${{ if eq(parameters.isOSSBuild, true) }}:
name: EssentialExperiencesOpenSource-windows-2022
${{ if eq(parameters.isOSSBuild, false) }}:
name: EssentialExperiences-windows-2022
variables:
skipComponentGovernanceDetection: true
steps:
@ -31,5 +35,5 @@ jobs:
- task: VSTest@2
displayName: Run CalculatorUnitTests
inputs:
testAssemblyVer2: $(Build.ArtifactStagingDirectory)\drop\Release\${{ parameters.platform }}\CalculatorUnitTests\AppPackages\CalculatorUnitTests_Test\CalculatorUnitTests.appx
testAssemblyVer2: $(Build.ArtifactStagingDirectory)\drop\Release\${{ parameters.platform }}\CalculatorUnitTests\AppPackages\CalculatorUnitTests_Test\CalculatorUnitTests.msix
otherConsoleOptions: /Platform:${{ parameters.platform }}

View file

@ -10,26 +10,26 @@
ARM\
Project\
AppPackages\
Project_ARM.appx
Project_scale-100.appx
Project_ARM.msix
Project_scale-100.msix
x64\
Project\
AppPackages\
Project_x64.appx
Project_scale-100.appx
Project_x64.msix
Project_scale-100.msix
.PARAMETER InputPath
The path where appx packages to bundle are located.
The path where msix packages to bundle are located.
.PARAMETER ProjectName
The folder name within each architecture to search recursively for appx packages. The appx files
The folder name within each architecture to search recursively for msix packages. The msix files
must also have the ProjectName in their file names.
.PARAMETER OutputFile
The path to write the generated mapping file.
.EXAMPLE
Create-AppxBundleMapping -InputPath "C:\drop" -ProjectName "CalculatorApp" -OutputFile "C:\Temp\AppxBundleMapping.txt"
Create-MsixBundleMapping -InputPath "C:\drop" -ProjectName "CalculatorApp" -OutputFile "C:\Temp\MsixBundleMapping.txt"
#>
param(
[Parameter(Mandatory)]
@ -45,7 +45,7 @@ param(
$OutputFile
)
# List all appx packages by architecture
# List all msix packages by architecture
$architectures = @(Get-ChildItem -Path $InputPath -Directory | Foreach-Object Name | Foreach-Object ToLower)
if ($architectures.Count -lt 1)
{
@ -57,22 +57,22 @@ $packages = @{}
foreach ($architecture in $architectures)
{
$projectPath = [IO.Path]::Combine($InputPath, $architecture, $ProjectName)
$packages[$architecture] = Get-ChildItem -Path $projectPath -Recurse -Filter *$ProjectName*.appx
$packages[$architecture] = Get-ChildItem -Path $projectPath -Recurse -Filter *$ProjectName*.msix
if ($packages[$architecture].Count -lt 1)
{
throw "No .appx files found for architecture $architecture in $projectPath"
throw "No .msix files found for architecture $architecture in $projectPath"
}
}
# List appx packages which are common to all architectures
# List msix packages which are common to all architectures
$commonPackages = $packages[$defaultArchitecture]
foreach ($architecture in $architectures)
{
$commonPackages = $packages[$architecture] | Where {$commonPackages.Name -Contains $_.Name}
}
# List appx packages which are architecture-specific and verify that there is exactly one per
# List msix packages which are architecture-specific and verify that there is exactly one per
# architecture.
$architectureSpecificPackages = @()
if ($architectures.Count -gt 1)

View file

@ -0,0 +1,22 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.
<#
.SYNOPSIS
Disables animations on the system. Equivalent to turning off the "Animation effects" setting in the Windows Settings app.
#>
Add-Type -AssemblyName System.Runtime.WindowsRuntime
$asTaskGeneric = ([System.WindowsRuntimeSystemExtensions].GetMethods() | ? { $_.Name -eq 'AsTask' -and $_.GetParameters().Count -eq 1 -and $_.GetParameters()[0].ParameterType.Name -eq 'IAsyncOperation`1' })[0]
Function WaitForAsyncAction($WinRtTask, $ResultType) {
$asTask = $asTaskGeneric.MakeGenericMethod($ResultType)
$task = $asTask.Invoke($null, @($WinRtTask))
$task.GetAwaiter().GetResult()
}
[Windows.UI.ViewManagement.Core.UISettingsController,Windows.UI.ViewManagement.Core,ContentType=WindowsRuntime] | Out-Null
$controller = WaitForAsyncAction ([Windows.UI.ViewManagement.Core.UISettingsController]::RequestDefaultAsync()) ([Windows.UI.ViewManagement.Core.UISettingsController])
$controller.SetAnimationsEnabled($false)

View file

@ -21,11 +21,11 @@ that build into the final Calculator application.
The View layer is contained in the [Calculator project][Calculator folder]. This project contains mostly XAML files
and various custom controls that support the UI. [App.xaml][App.xaml] contains many of the [static][StaticResource] and
[theme][ThemeResource] resources that the other XAML files will reference. Its code-behind file, [App.xaml.cpp][App.xaml.cpp],
[theme][ThemeResource] resources that the other XAML files will reference. Its code-behind file, [App.xaml.cs][App.xaml.cs],
contains the main entry point to the application. On startup, it navigates to the main page.
```C++
rootFrame->Navigate(MainPage::typeid, argument)
```C#
rootFrame.Navigate(typeof(MainPage), argument)
```
In Calculator, there is only one concrete [Page][Page] class: [MainPage.xaml][MainPage.xaml]. `MainPage` is the root
@ -166,7 +166,7 @@ instead of regular floating point arithmetic). The interface to this layer is de
[Calculator folder]: ../src/Calculator
[App.xaml]: ../src/Calculator/App.xaml
[App.xaml.cpp]: ../src/Calculator/App.xaml.cpp
[App.xaml.cs]: ../src/Calculator/App.xaml.cs
[StaticResource]: https://docs.microsoft.com/en-us/windows/uwp/xaml-platform/staticresource-markup-extension
[ThemeResource]: https://docs.microsoft.com/en-us/windows/uwp/xaml-platform/themeresource-markup-extension
[Page]: https://docs.microsoft.com/en-us/uwp/api/Windows.UI.Xaml.Controls.Page

BIN
docs/Images/CalculatorScreenshot.png Normal file → Executable file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 256 KiB

After

Width:  |  Height:  |  Size: 81 KiB

Before After
Before After

View file

@ -10,9 +10,9 @@ In 2021, the Windows Calculator team is focused on:
* Migrating the codebase to C# ([#893](https://github.com/microsoft/calculator/issues/893))
* Releasing infinite-precision engine as standalone package ([#1545](https://github.com/microsoft/calculator/issues/1545)) and adding support for arbitrary expression parsing ([#526](https://github.com/microsoft/calculator/issues/526))
* Adding a settings page ([#596](https://github.com/microsoft/calculator/issues/596))
* [Your feature idea here] - please review our [new feature development process](https://github.com/Microsoft/calculator/blob/master/docs/NewFeatureProcess.md) to get started!
* [Your feature idea here] - please review our [new feature development process](https://github.com/Microsoft/calculator/blob/main/docs/NewFeatureProcess.md) to get started!
We welcome contributions of all kinds from the community, but especially those that support the efforts above. Please see our [contributing guidelines](https://github.com/Microsoft/calculator/blob/master/CONTRIBUTING.md) for more information on how to get involved.
We welcome contributions of all kinds from the community, but especially those that support the efforts above. Please see our [contributing guidelines](https://github.com/Microsoft/calculator/blob/main/CONTRIBUTING.md) for more information on how to get involved.
## Releases

View file

@ -1,6 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<config>
<add key="repositorypath" value=".\packages" />
</config>
</configuration>
<packageSources>
<clear />
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
<add key="Toolkit Labs" value="https://pkgs.dev.azure.com/dotnet/CommunityToolkit/_packaging/CommunityToolkit-Labs/nuget/v3/index.json" />
</packageSources>
<disabledPackageSources>
<clear />
</disabledPackageSources>
</configuration>

View file

@ -143,14 +143,14 @@ void CHistoryCollector::AddBinOpToHistory(int nOpCode, bool isIntegerMode, bool
// This is expected to be called when a binary op in the last say 1+2+ is changing to another one say 1+2* (+ changed to *)
// It needs to know by this change a Precedence inversion happened. i.e. previous op was lower or equal to its previous op, but the new
// one isn't. (Eg. 1*2* to 1*2^). It can add explicit brackets to ensure the precedence is inverted. (Eg. (1*2) ^)
void CHistoryCollector::ChangeLastBinOp(int nOpCode, bool fPrecInvToHigher, bool isIntgerMode)
void CHistoryCollector::ChangeLastBinOp(int nOpCode, bool fPrecInvToHigher, bool isIntegerMode)
{
TruncateEquationSzFromIch(m_lastBinOpStartIndex);
if (fPrecInvToHigher)
{
EnclosePrecInversionBrackets();
}
AddBinOpToHistory(nOpCode, isIntgerMode);
AddBinOpToHistory(nOpCode, isIntegerMode);
}
void CHistoryCollector::PushLastOpndStart(int ichOpndStart)

View file

@ -22,10 +22,9 @@ namespace CalcEngine
Number::Number(PNUMBER p) noexcept
: m_sign{ p->sign }
, m_exp{ p->exp }
, m_mantissa{}
{
m_mantissa.reserve(p->cdigit);
copy(p->mant, p->mant + p->cdigit, back_inserter(m_mantissa));
copy_n(p->mant, p->cdigit, back_inserter(m_mantissa));
}
PNUMBER Number::ToPNUMBER() const

View file

@ -101,7 +101,7 @@ CCalcEngine::CCalcEngine(
{
InitChopNumbers();
m_dwWordBitWidth = DwWordBitWidthFromeNumWidth(m_numwidth);
m_dwWordBitWidth = DwWordBitWidthFromNumWidth(m_numwidth);
m_maxTrigonometricNum = RationalMath::Pow(10, 100);

View file

@ -18,7 +18,6 @@
#include <sstream>
#include "Header Files/CalcEngine.h"
#include "Header Files/CalcUtils.h"
#include "NumberFormattingUtils.h"
using namespace std;
using namespace CalcEngine;
@ -31,17 +30,31 @@ namespace
// 0 is returned. Higher the number, higher the precedence of the operator.
int NPrecedenceOfOp(int nopCode)
{
static uint16_t rgbPrec[] = { 0, 0, IDC_OR, 0, IDC_XOR, 0, IDC_AND, 1, IDC_NAND, 1, IDC_NOR, 1, IDC_ADD, 2, IDC_SUB, 2, IDC_RSHF, 3,
IDC_LSHF, 3, IDC_RSHFL, 3, IDC_MOD, 3, IDC_DIV, 3, IDC_MUL, 3, IDC_PWR, 4, IDC_ROOT, 4, IDC_LOGBASEY, 4 };
for (unsigned int iPrec = 0; iPrec < size(rgbPrec); iPrec += 2)
switch (nopCode)
{
if (nopCode == rgbPrec[iPrec])
{
return rgbPrec[iPrec + 1];
}
default:
case IDC_OR:
case IDC_XOR:
return 0;
case IDC_AND:
case IDC_NAND:
case IDC_NOR:
return 1;
case IDC_ADD:
case IDC_SUB:
return 2;
case IDC_LSHF:
case IDC_RSHF:
case IDC_RSHFL:
case IDC_MOD:
case IDC_DIV:
case IDC_MUL:
return 3;
case IDC_PWR:
case IDC_ROOT:
case IDC_LOGBASEY:
return 4;
}
return 0;
}
}
@ -519,6 +532,12 @@ void CCalcEngine::ProcessCommandWorker(OpCode wParam)
if (wParam == IDC_OPENP)
{
// if there's an omitted multiplication sign
if (IsDigitOpCode(m_nLastCom) || IsUnaryOpCode(m_nLastCom) || m_nLastCom == IDC_PNT || m_nLastCom == IDC_CLOSEP)
{
ProcessCommand(IDC_MUL);
}
CheckAndAddLastBinOpToHistory();
m_HistoryCollector.AddOpenBraceToHistory();
@ -594,7 +613,7 @@ void CCalcEngine::ProcessCommandWorker(OpCode wParam)
// Set the "(=xx" indicator.
if (nullptr != m_pCalcDisplay)
{
m_pCalcDisplay->SetParenthesisNumber(m_openParenCount >= 0 ? static_cast<unsigned int>(m_openParenCount) : 0);
m_pCalcDisplay->SetParenthesisNumber(static_cast<unsigned int>(m_openParenCount));
}
if (!m_bError)
@ -757,7 +776,7 @@ void CCalcEngine::ProcessCommandWorker(OpCode wParam)
break;
case IDC_FE:
// Toggle exponential notation display.
m_nFE = NumberFormat(!(int)m_nFE);
m_nFE = m_nFE == NumberFormat::Float ? NumberFormat::Scientific : NumberFormat::Float;
DisplayNum();
break;

View file

@ -39,7 +39,7 @@ void CCalcEngine::SetRadixTypeAndNumWidth(RadixType radixtype, NUM_WIDTH numwidt
if (numwidth >= NUM_WIDTH::QWORD_WIDTH && numwidth <= NUM_WIDTH::BYTE_WIDTH)
{
m_numwidth = numwidth;
m_dwWordBitWidth = DwWordBitWidthFromeNumWidth(numwidth);
m_dwWordBitWidth = DwWordBitWidthFromNumWidth(numwidth);
}
// inform ratpak that a change in base or precision has occurred
@ -50,7 +50,7 @@ void CCalcEngine::SetRadixTypeAndNumWidth(RadixType radixtype, NUM_WIDTH numwidt
DisplayNum();
}
int32_t CCalcEngine::DwWordBitWidthFromeNumWidth(NUM_WIDTH numwidth)
int32_t CCalcEngine::DwWordBitWidthFromNumWidth(NUM_WIDTH numwidth)
{
switch (numwidth)
{
@ -85,7 +85,7 @@ uint32_t CCalcEngine::NRadixFromRadixType(RadixType radixtype)
// Toggles a given bit into the number representation. returns true if it changed it actually.
bool CCalcEngine::TryToggleBit(CalcEngine::Rational& rat, uint32_t wbitno)
{
uint32_t wmax = DwWordBitWidthFromeNumWidth(m_numwidth);
uint32_t wmax = DwWordBitWidthFromNumWidth(m_numwidth);
if (wbitno >= wmax)
{
return false; // ignore error cant happen

View file

@ -45,8 +45,8 @@
<AppContainerApplication>true</AppContainerApplication>
<ApplicationType>Windows Store</ApplicationType>
<ApplicationTypeRevision>10.0</ApplicationTypeRevision>
<WindowsTargetPlatformVersion Condition="'$(WindowsTargetPlatformVersion)' == ''">10.0.18362.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformMinVersion>10.0.17134.0</WindowsTargetPlatformMinVersion>
<WindowsTargetPlatformVersion Condition="'$(WindowsTargetPlatformVersion)' == ''">10.0.22621.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformMinVersion>10.0.19041.0</WindowsTargetPlatformMinVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<!-- This has to be exactly in this place for this to work -->
@ -56,28 +56,28 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<PlatformToolset>v143</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<PlatformToolset>v143</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<PlatformToolset>v143</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<PlatformToolset>v143</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v142</PlatformToolset>
<PlatformToolset>v143</PlatformToolset>
<CodeAnalysisRuleSet>NativeRecommendedRules.ruleset</CodeAnalysisRuleSet>
<RunCodeAnalysis>true</RunCodeAnalysis>
</PropertyGroup>
@ -85,7 +85,7 @@
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v142</PlatformToolset>
<PlatformToolset>v143</PlatformToolset>
<CodeAnalysisRuleSet>NativeRecommendedRules.ruleset</CodeAnalysisRuleSet>
<RunCodeAnalysis>true</RunCodeAnalysis>
</PropertyGroup>
@ -93,7 +93,7 @@
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v142</PlatformToolset>
<PlatformToolset>v143</PlatformToolset>
<CodeAnalysisRuleSet>NativeRecommendedRules.ruleset</CodeAnalysisRuleSet>
<RunCodeAnalysis>true</RunCodeAnalysis>
</PropertyGroup>
@ -101,7 +101,7 @@
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v142</PlatformToolset>
<PlatformToolset>v143</PlatformToolset>
<CodeAnalysisRuleSet>NativeRecommendedRules.ruleset</CodeAnalysisRuleSet>
<RunCodeAnalysis>true</RunCodeAnalysis>
</PropertyGroup>
@ -346,4 +346,4 @@
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets" />
</Project>
</Project>

View file

@ -79,7 +79,7 @@ vector<shared_ptr<HISTORYITEM>> const& CalculatorHistory::GetHistory()
shared_ptr<HISTORYITEM> const& CalculatorHistory::GetHistoryItem(unsigned int uIdx)
{
assert(uIdx >= 0 && uIdx < m_historyItems.size());
assert(uIdx < m_historyItems.size());
return m_historyItems.at(uIdx);
}

View file

@ -179,7 +179,7 @@ private:
CalcEngine::Rational SciCalcFunctions(CalcEngine::Rational const& rat, uint32_t op);
CalcEngine::Rational DoOperation(int operation, CalcEngine::Rational const& lhs, CalcEngine::Rational const& rhs);
void SetRadixTypeAndNumWidth(RadixType radixtype, NUM_WIDTH numwidth);
int32_t DwWordBitWidthFromeNumWidth(NUM_WIDTH numwidth);
int32_t DwWordBitWidthFromNumWidth(NUM_WIDTH numwidth);
uint32_t NRadixFromRadixType(RadixType radixtype);
double GenerateRandomNumber();

View file

@ -21,8 +21,8 @@ public:
~CHistoryCollector();
void AddOpndToHistory(std::wstring_view numStr, CalcEngine::Rational const& rat, bool fRepetition = false);
void RemoveLastOpndFromHistory();
void AddBinOpToHistory(int nOpCode, bool isIntgerMode, bool fNoRepetition = true);
void ChangeLastBinOp(int nOpCode, bool fPrecInvToHigher, bool isIntgerMode);
void AddBinOpToHistory(int nOpCode, bool isIntegerMode, bool fNoRepetition = true);
void ChangeLastBinOp(int nOpCode, bool fPrecInvToHigher, bool isIntegerMode);
void AddUnaryOpToHistory(int nOpCode, bool fInv, AngleType angletype);
void AddOpenBraceToHistory();
void AddCloseBraceToHistory();

View file

@ -3,7 +3,7 @@
using namespace std;
namespace CalcManager::NumberFormattingUtils
namespace UnitConversionManager::NumberFormattingUtils
{
/// <summary>
/// Trims out any trailing zeros or decimals in the given input string

View file

@ -6,7 +6,7 @@
#include <string>
#include "sal_cross_platform.h"
namespace CalcManager::NumberFormattingUtils
namespace UnitConversionManager::NumberFormattingUtils
{
void TrimTrailingZeros(_Inout_ std::wstring& input);
unsigned int GetNumberDigits(std::wstring value);

View file

@ -3,6 +3,8 @@
#pragma once
#include <cstdint>
// CalcErr.h
//
// Defines the error codes thrown by ratpak and caught by Calculator
@ -36,7 +38,7 @@
// This format is based loosely on an OLE HRESULT and is compatible with the
// SUCCEEDED and FAILED macros as well as the HRESULT_CODE macro
typedef int32_t ResultCode;
using ResultCode = int32_t;
// CALC_E_DIVIDEBYZERO
//

View file

@ -25,7 +25,7 @@
using namespace std;
void _readconstants(void);
void _readconstants();
#if defined(GEN_CONST)
static int cbitsofprecision = 0;
@ -136,13 +136,7 @@ void ChangeConstants(uint32_t radix, int32_t precision)
// in the internal BASEX radix, this is important for length calculations
// in translating from radix to BASEX and back.
uint64_t limit = static_cast<uint64_t>(BASEX) / static_cast<uint64_t>(radix);
g_ratio = 0;
for (uint32_t digit = 1; digit < limit; digit *= radix)
{
g_ratio++;
}
g_ratio += !g_ratio;
g_ratio = static_cast<int32_t>(ceil(BASEXPWR / log2(radix))) - 1;
destroyrat(rat_nRadix);
rat_nRadix = i32torat(radix);

View file

@ -11,7 +11,7 @@
using namespace std;
using namespace UnitConversionManager;
using namespace CalcManager::NumberFormattingUtils;
using namespace UnitConversionManager::NumberFormattingUtils;
static constexpr uint32_t EXPECTEDSERIALIZEDCATEGORYTOKENCOUNT = 3U;
static constexpr uint32_t EXPECTEDSERIALIZEDUNITTOKENCOUNT = 6U;

View file

@ -156,13 +156,12 @@ namespace UnitConversionManager
std::wstring targetCurrencyCode;
};
typedef std::tuple<std::vector<UnitConversionManager::Unit>, UnitConversionManager::Unit, UnitConversionManager::Unit> CategorySelectionInitializer;
typedef std::unordered_map<
using CategorySelectionInitializer = std::tuple<std::vector<UnitConversionManager::Unit>, UnitConversionManager::Unit, UnitConversionManager::Unit>;
using UnitToUnitToConversionDataMap = std::unordered_map<
UnitConversionManager::Unit,
std::unordered_map<UnitConversionManager::Unit, UnitConversionManager::ConversionData, UnitConversionManager::UnitHash>,
UnitConversionManager::UnitHash>
UnitToUnitToConversionDataMap;
typedef std::unordered_map<int, std::vector<UnitConversionManager::Unit>> CategoryToUnitVectorMap;
UnitConversionManager::UnitHash>;
using CategoryToUnitVectorMap = std::unordered_map<int, std::vector<UnitConversionManager::Unit>>;
class IViewModelCurrencyCallback
{

View file

@ -12,8 +12,8 @@
#include "DataLoaders/UnitConverterDataLoader.h"
using namespace CalculatorApp;
using namespace CalculatorApp::Common;
using namespace CalculatorApp::DataLoaders;
using namespace CalculatorApp::ViewModel::Common;
using namespace CalculatorApp::ViewModel::DataLoaders;
using namespace CalculatorApp::ViewModel;
using namespace CalculationManager;
using namespace Platform;
@ -75,7 +75,7 @@ void ApplicationViewModel::Categories::set(IObservableVector<NavCategoryGroup ^>
void ApplicationViewModel::Initialize(ViewMode mode)
{
if (!NavCategory::IsValidViewMode(mode) || !NavCategory::IsViewModeEnabled(mode))
if (!NavCategoryStates::IsValidViewMode(mode) || !NavCategoryStates::IsViewModeEnabled(mode))
{
mode = ViewMode::Standard;
}
@ -124,7 +124,7 @@ bool ApplicationViewModel::TryRecoverFromNavigationModeFailure()
void ApplicationViewModel::OnModeChanged()
{
assert(NavCategory::IsValidViewMode(m_mode));
assert(NavCategoryStates::IsValidViewMode(m_mode));
if (NavCategory::IsCalculatorViewMode(m_mode))
{
if (!m_CalculatorViewModel)
@ -160,15 +160,15 @@ void ApplicationViewModel::OnModeChanged()
}
auto resProvider = AppResourceProvider::GetInstance();
CategoryName = resProvider->GetResourceString(NavCategory::GetNameResourceKey(m_mode));
CategoryName = resProvider->GetResourceString(NavCategoryStates::GetNameResourceKey(m_mode));
// Cast mode to an int in order to save it to app data.
// Save the changed mode, so that the new window launches in this mode.
// Don't save until after we have adjusted to the new mode, so we don't save a mode that fails to load.
ApplicationData::Current->LocalSettings->Values->Insert(ModePropertyName, NavCategory::Serialize(m_mode));
ApplicationData::Current->LocalSettings->Values->Insert(ModePropertyName, NavCategoryStates::Serialize(m_mode));
// Log ModeChange event when not first launch, log WindowCreated on first launch
if (NavCategory::IsValidViewMode(m_PreviousMode))
if (NavCategoryStates::IsValidViewMode(m_PreviousMode))
{
TraceLogger::GetInstance()->LogModeChange(m_mode);
}
@ -213,7 +213,7 @@ void ApplicationViewModel::SetMenuCategories()
// Use the Categories property instead of the backing variable
// because we want to take advantage of binding updates and
// property setter logic.
Categories = NavCategoryGroup::CreateMenuOptions();
Categories = NavCategoryStates::CreateMenuOptions();
}
void ApplicationViewModel::ToggleAlwaysOnTop(float width, float height)

View file

@ -17,14 +17,14 @@ namespace CalculatorApp
public:
ApplicationViewModel();
void Initialize(CalculatorApp::Common::ViewMode mode); // Use for first init, use deserialize for rehydration
void Initialize(CalculatorApp::ViewModel::Common::ViewMode mode); // Use for first init, use deserialize for rehydration
OBSERVABLE_OBJECT();
OBSERVABLE_PROPERTY_RW(StandardCalculatorViewModel ^, CalculatorViewModel);
OBSERVABLE_PROPERTY_RW(DateCalculatorViewModel ^, DateCalcViewModel);
OBSERVABLE_PROPERTY_RW(GraphingCalculatorViewModel ^, GraphingCalcViewModel);
OBSERVABLE_PROPERTY_RW(UnitConverterViewModel ^, ConverterViewModel);
OBSERVABLE_PROPERTY_RW(CalculatorApp::Common::ViewMode, PreviousMode);
OBSERVABLE_PROPERTY_RW(CalculatorApp::ViewModel::Common::ViewMode, PreviousMode);
OBSERVABLE_PROPERTY_R(bool, IsAlwaysOnTop);
OBSERVABLE_NAMED_PROPERTY_RW(Platform::String ^, CategoryName);
@ -34,14 +34,14 @@ namespace CalculatorApp
COMMAND_FOR_METHOD(CopyCommand, ApplicationViewModel::OnCopyCommand);
COMMAND_FOR_METHOD(PasteCommand, ApplicationViewModel::OnPasteCommand);
property CalculatorApp::Common::ViewMode Mode
property CalculatorApp::ViewModel::Common::ViewMode Mode
{
CalculatorApp::Common::ViewMode get()
CalculatorApp::ViewModel::Common::ViewMode get()
{
return m_mode;
}
void set(CalculatorApp::Common::ViewMode value);
void set(CalculatorApp::ViewModel::Common::ViewMode value);
}
static property Platform::String^ ModePropertyName
{
@ -51,21 +51,21 @@ namespace CalculatorApp
}
}
property Windows::Foundation::Collections::IObservableVector<CalculatorApp::Common::NavCategoryGroup^>^ Categories
property Windows::Foundation::Collections::IObservableVector<CalculatorApp::ViewModel::Common::NavCategoryGroup^>^ Categories
{
Windows::Foundation::Collections::IObservableVector<CalculatorApp::Common::NavCategoryGroup^>^ get()
Windows::Foundation::Collections::IObservableVector<CalculatorApp::ViewModel::Common::NavCategoryGroup^>^ get()
{
return m_categories;
}
void set(Windows::Foundation::Collections::IObservableVector<CalculatorApp::Common::NavCategoryGroup^>^ value);
void set(Windows::Foundation::Collections::IObservableVector<CalculatorApp::ViewModel::Common::NavCategoryGroup^>^ value);
}
property Windows::UI::Xaml::Visibility ClearMemoryVisibility
{
Windows::UI::Xaml::Visibility get()
{
return CalculatorApp::Common::NavCategory::IsCalculatorViewMode(Mode) ? Windows::UI::Xaml::Visibility::Visible
return CalculatorApp::ViewModel::Common::NavCategory::IsCalculatorViewMode(Mode) ? Windows::UI::Xaml::Visibility::Visible
: Windows::UI::Xaml::Visibility::Collapsed;
}
}
@ -106,8 +106,8 @@ namespace CalculatorApp
void SetMenuCategories();
CalculatorApp::Common::ViewMode m_mode;
Windows::Foundation::Collections::IObservableVector<CalculatorApp::Common::NavCategoryGroup ^> ^ m_categories;
CalculatorApp::ViewModel::Common::ViewMode m_mode;
Windows::Foundation::Collections::IObservableVector<CalculatorApp::ViewModel::Common::NavCategoryGroup ^> ^ m_categories;
Concurrency::task<void> HandleToggleAlwaysOnTop(float width, float height);
void SetDisplayNormalAlwaysOnTopOption();
};

View file

@ -1,9 +1,9 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#define APP_FILE_NAME "Calculator"
#define APP_FILE_NAME "CalcViewModel"
#define APP_FILE_IS_EXE
#define APP_PRODUCT_NAME "Microsoft Calculator"
#define APP_PRODUCT_NAME "Microsoft Calculator ViewModel"
#define APP_COMPANY_NAME "Microsoft Corporation"
#define APP_COPYRIGHT "\251 Microsoft Corporation. All rights reserved."

View file

@ -35,61 +35,61 @@
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{90e9761d-9262-4773-942d-caeae75d7140}</ProjectGuid>
<Keyword>StaticLibrary</Keyword>
<RootNamespace>CalcViewModel</RootNamespace>
<ProjectGuid>{812d1a7b-b8ac-49e4-8e6d-af5d59500d56}</ProjectGuid>
<Keyword>WindowsRuntimeComponent</Keyword>
<RootNamespace>CalculatorApp.ViewModel</RootNamespace>
<DefaultLanguage>en-US</DefaultLanguage>
<MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
<AppContainerApplication>true</AppContainerApplication>
<ApplicationType>Windows Store</ApplicationType>
<WindowsTargetPlatformVersion>10.0.18362.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformMinVersion>10.0.17134.0</WindowsTargetPlatformMinVersion>
<WindowsTargetPlatformVersion>10.0.22621.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformMinVersion>10.0.19041.0</WindowsTargetPlatformMinVersion>
<ApplicationTypeRevision>10.0</ApplicationTypeRevision>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<PlatformToolset>v143</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<PlatformToolset>v143</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<PlatformToolset>v143</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<PlatformToolset>v143</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v142</PlatformToolset>
<PlatformToolset>v143</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v142</PlatformToolset>
<PlatformToolset>v143</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v142</PlatformToolset>
<PlatformToolset>v143</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v142</PlatformToolset>
<PlatformToolset>v143</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
@ -105,13 +105,13 @@
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="PropertySheets">
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
@ -122,175 +122,181 @@
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup />
<PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<GenerateManifest>false</GenerateManifest>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<GenerateManifest>false</GenerateManifest>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">
<GenerateManifest>false</GenerateManifest>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">
<GenerateManifest>false</GenerateManifest>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
<GenerateManifest>false</GenerateManifest>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
<GenerateManifest>false</GenerateManifest>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<GenerateManifest>false</GenerateManifest>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<GenerateManifest>false</GenerateManifest>
<GenerateProjectSpecificOutputFolder>true</GenerateProjectSpecificOutputFolder>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<CompileAsWinRT>true</CompileAsWinRT>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>$(SolutionDir)..\src\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<DisableSpecificWarnings>4453</DisableSpecificWarnings>
<AdditionalOptions>/bigobj /await /std:c++17 /utf-8 %(AdditionalOptions)</AdditionalOptions>
<WarningLevel>Level4</WarningLevel>
<TreatWarningAsError>true</TreatWarningAsError>
<PreprocessorDefinitions>_WINRT_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<PrecompiledHeaderOutputFile>$(IntDir)pch.pch</PrecompiledHeaderOutputFile>
<AdditionalIncludeDirectories>$(SolutionDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalUsingDirectories>$(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories)</AdditionalUsingDirectories>
<AdditionalOptions>/bigobj /await %(AdditionalOptions)</AdditionalOptions>
<DisableSpecificWarnings>28204;4453</DisableSpecificWarnings>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<GenerateWindowsMetadata>false</GenerateWindowsMetadata>
</Link>
<Lib>
<AdditionalOptions>/ignore:4264 %(AdditionalOptions)</AdditionalOptions>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<CompileAsWinRT>true</CompileAsWinRT>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>$(SolutionDir)..\src\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<DisableSpecificWarnings>4453</DisableSpecificWarnings>
<AdditionalOptions>/bigobj /await /std:c++17 /utf-8 %(AdditionalOptions)</AdditionalOptions>
<WarningLevel>Level4</WarningLevel>
<TreatWarningAsError>true</TreatWarningAsError>
<PreprocessorDefinitions>_WINRT_DLL;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<PrecompiledHeaderOutputFile>$(IntDir)pch.pch</PrecompiledHeaderOutputFile>
<AdditionalIncludeDirectories>$(SolutionDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalUsingDirectories>$(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories)</AdditionalUsingDirectories>
<AdditionalOptions>/bigobj /await %(AdditionalOptions)</AdditionalOptions>
<DisableSpecificWarnings>28204;4453</DisableSpecificWarnings>
<LanguageStandard>stdcpp17</LanguageStandard>
<ControlFlowGuard>Guard</ControlFlowGuard>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<GenerateWindowsMetadata>false</GenerateWindowsMetadata>
</Link>
<Lib>
<AdditionalOptions>/ignore:4264 %(AdditionalOptions)</AdditionalOptions>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|arm'">
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<CompileAsWinRT>true</CompileAsWinRT>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>$(SolutionDir)..\src\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<DisableSpecificWarnings>4453</DisableSpecificWarnings>
<AdditionalOptions>/bigobj /await /std:c++17 /utf-8 %(AdditionalOptions)</AdditionalOptions>
<WarningLevel>Level4</WarningLevel>
<TreatWarningAsError>true</TreatWarningAsError>
<PreprocessorDefinitions>_WINRT_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<PrecompiledHeaderOutputFile>$(IntDir)pch.pch</PrecompiledHeaderOutputFile>
<AdditionalIncludeDirectories>$(SolutionDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalUsingDirectories>$(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories)</AdditionalUsingDirectories>
<AdditionalOptions>/bigobj /await %(AdditionalOptions)</AdditionalOptions>
<DisableSpecificWarnings>28204;4453</DisableSpecificWarnings>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<GenerateWindowsMetadata>false</GenerateWindowsMetadata>
</Link>
<Lib>
<AdditionalOptions>/ignore:4264 %(AdditionalOptions)</AdditionalOptions>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|arm'">
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<CompileAsWinRT>true</CompileAsWinRT>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>$(SolutionDir)..\src\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<DisableSpecificWarnings>4453</DisableSpecificWarnings>
<AdditionalOptions>/bigobj /await /std:c++17 /utf-8 %(AdditionalOptions)</AdditionalOptions>
<WarningLevel>Level4</WarningLevel>
<TreatWarningAsError>true</TreatWarningAsError>
<PreprocessorDefinitions>_WINRT_DLL;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<PrecompiledHeaderOutputFile>$(IntDir)pch.pch</PrecompiledHeaderOutputFile>
<AdditionalIncludeDirectories>$(SolutionDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalUsingDirectories>$(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories)</AdditionalUsingDirectories>
<AdditionalOptions>/bigobj /await %(AdditionalOptions)</AdditionalOptions>
<DisableSpecificWarnings>28204;4453</DisableSpecificWarnings>
<LanguageStandard>stdcpp17</LanguageStandard>
<ControlFlowGuard>Guard</ControlFlowGuard>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<PreprocessorDefinitions>_WINRT_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<PrecompiledHeaderOutputFile>$(IntDir)pch.pch</PrecompiledHeaderOutputFile>
<AdditionalIncludeDirectories>$(SolutionDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalUsingDirectories>$(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories)</AdditionalUsingDirectories>
<AdditionalOptions>/bigobj /await %(AdditionalOptions)</AdditionalOptions>
<DisableSpecificWarnings>28204;4453</DisableSpecificWarnings>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<PreprocessorDefinitions>_WINRT_DLL;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<PrecompiledHeaderOutputFile>$(IntDir)pch.pch</PrecompiledHeaderOutputFile>
<AdditionalIncludeDirectories>$(SolutionDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalUsingDirectories>$(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories)</AdditionalUsingDirectories>
<AdditionalOptions>/bigobj /await %(AdditionalOptions)</AdditionalOptions>
<DisableSpecificWarnings>28204;4453</DisableSpecificWarnings>
<LanguageStandard>stdcpp17</LanguageStandard>
<ControlFlowGuard>Guard</ControlFlowGuard>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<GenerateWindowsMetadata>false</GenerateWindowsMetadata>
</Link>
<Lib>
<AdditionalOptions>/ignore:4264 %(AdditionalOptions)</AdditionalOptions>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<CompileAsWinRT>true</CompileAsWinRT>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>$(SolutionDir)..\src\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<DisableSpecificWarnings>4453</DisableSpecificWarnings>
<AdditionalOptions>/bigobj /await /std:c++17 /utf-8 %(AdditionalOptions)</AdditionalOptions>
<WarningLevel>Level4</WarningLevel>
<TreatWarningAsError>true</TreatWarningAsError>
<PreprocessorDefinitions>_WINRT_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<PrecompiledHeaderOutputFile>$(IntDir)pch.pch</PrecompiledHeaderOutputFile>
<AdditionalIncludeDirectories>$(SolutionDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalUsingDirectories>$(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories)</AdditionalUsingDirectories>
<AdditionalOptions>/bigobj /await %(AdditionalOptions)</AdditionalOptions>
<DisableSpecificWarnings>28204;4453</DisableSpecificWarnings>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<GenerateWindowsMetadata>false</GenerateWindowsMetadata>
</Link>
<Lib>
<AdditionalOptions>/ignore:4264 %(AdditionalOptions)</AdditionalOptions>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<CompileAsWinRT>true</CompileAsWinRT>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>$(SolutionDir)..\src\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<DisableSpecificWarnings>4453</DisableSpecificWarnings>
<AdditionalOptions>/bigobj /await /std:c++17 /utf-8 %(AdditionalOptions)</AdditionalOptions>
<WarningLevel>Level4</WarningLevel>
<TreatWarningAsError>true</TreatWarningAsError>
<PreprocessorDefinitions>_WINRT_DLL;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<PrecompiledHeaderOutputFile>$(IntDir)pch.pch</PrecompiledHeaderOutputFile>
<AdditionalIncludeDirectories>$(SolutionDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalUsingDirectories>$(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories)</AdditionalUsingDirectories>
<AdditionalOptions>/bigobj /await %(AdditionalOptions)</AdditionalOptions>
<DisableSpecificWarnings>28204;4453</DisableSpecificWarnings>
<LanguageStandard>stdcpp17</LanguageStandard>
<ControlFlowGuard>Guard</ControlFlowGuard>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<GenerateWindowsMetadata>false</GenerateWindowsMetadata>
</Link>
<Lib>
<AdditionalOptions>/ignore:4264 %(AdditionalOptions)</AdditionalOptions>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|arm64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<CompileAsWinRT>true</CompileAsWinRT>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>$(SolutionDir)..\src\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<DisableSpecificWarnings>4453</DisableSpecificWarnings>
<AdditionalOptions>/bigobj /await /std:c++17 /utf-8 %(AdditionalOptions)</AdditionalOptions>
<WarningLevel>Level4</WarningLevel>
<TreatWarningAsError>true</TreatWarningAsError>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<GenerateWindowsMetadata>false</GenerateWindowsMetadata>
</Link>
<Lib>
<AdditionalOptions>/ignore:4264 %(AdditionalOptions)</AdditionalOptions>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|arm64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<CompileAsWinRT>true</CompileAsWinRT>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>$(SolutionDir)..\src\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<DisableSpecificWarnings>4453</DisableSpecificWarnings>
<AdditionalOptions>/bigobj /await /std:c++17 /utf-8 %(AdditionalOptions)</AdditionalOptions>
<WarningLevel>Level4</WarningLevel>
<TreatWarningAsError>true</TreatWarningAsError>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<GenerateWindowsMetadata>false</GenerateWindowsMetadata>
</Link>
<Lib>
<AdditionalOptions>/ignore:4264 %(AdditionalOptions)</AdditionalOptions>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(IsStoreBuild)' == 'True'">
<ClCompile>
<AdditionalOptions>/DSEND_DIAGNOSTICS %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
</ItemDefinitionGroup>
<PropertyGroup>
<Version Condition="'$(Version)' == ''">0.0.0.0</Version>
</PropertyGroup>
<ItemGroup>
<ResourceCompile Include="CalcViewModel.rc" PreprocessorDefinitions="%(PreprocessorDefinitions);APP_VERSION_MAJOR=$(Version.Split(`.`)[0]);APP_VERSION_MINOR=$(Version.Split(`.`)[1]);APP_VERSION_BUILD=$(Version.Split(`.`)[2]);APP_VERSION_REVISION=$(Version.Split(`.`)[3])" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="ApplicationViewModel.h" />
<ClInclude Include="Common\AppResourceProvider.h" />
@ -314,6 +320,7 @@
<ClInclude Include="Common\NavCategory.h" />
<ClInclude Include="Common\NetworkManager.h" />
<ClInclude Include="Common\NumberBase.h" />
<ClInclude Include="Common\RadixType.h" />
<ClInclude Include="Common\TraceLogger.h" />
<ClInclude Include="Common\Utils.h" />
<ClInclude Include="DataLoaders\CurrencyDataLoader.h" />
@ -350,6 +357,7 @@
<ClCompile Include="Common\LocalizationService.cpp" />
<ClCompile Include="Common\NavCategory.cpp" />
<ClCompile Include="Common\NetworkManager.cpp" />
<ClCompile Include="Common\RadixType.cpp" />
<ClCompile Include="Common\TraceLogger.cpp" />
<ClCompile Include="Common\Utils.cpp" />
<ClCompile Include="DataLoaders\CurrencyDataLoader.cpp" />
@ -365,10 +373,10 @@
<ClCompile Include="pch.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
</ClCompile>
@ -407,5 +415,6 @@
<None Include="DataLoaders\DefaultFromToCurrency.json" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View file

@ -2,27 +2,20 @@
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Common">
<UniqueIdentifier>{1daab7c4-63f6-4266-a259-f34acad66d09}</UniqueIdentifier>
<UniqueIdentifier>{05fb7833-4679-4430-bf21-808354e815bf}</UniqueIdentifier>
</Filter>
<Filter Include="Common\Automation">
<UniqueIdentifier>{8d4edf06-c312-4312-978a-b6c2beb8295a}</UniqueIdentifier>
<UniqueIdentifier>{8f1ef587-e5ce-4fc2-b9b7-73326d5e779a}</UniqueIdentifier>
</Filter>
<Filter Include="DataLoaders">
<UniqueIdentifier>{0184f727-b8aa-4af8-a699-63f1b56e7853}</UniqueIdentifier>
<UniqueIdentifier>{70216695-3d7b-451a-98e4-cacbea3ba0a6}</UniqueIdentifier>
</Filter>
<Filter Include="GraphingCalculator">
<UniqueIdentifier>{cf7dca32-9727-4f98-83c3-1c0ca7dd1e0c}</UniqueIdentifier>
<UniqueIdentifier>{9b94309f-6b9b-4cbb-8584-4273061cc432}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="pch.cpp" />
<ClCompile Include="ApplicationViewModel.cpp" />
<ClCompile Include="DateCalculatorViewModel.cpp" />
<ClCompile Include="HistoryItemViewModel.cpp" />
<ClCompile Include="HistoryViewModel.cpp" />
<ClCompile Include="MemoryItemViewModel.cpp" />
<ClCompile Include="StandardCalculatorViewModel.cpp" />
<ClCompile Include="UnitConverterViewModel.cpp" />
<ClCompile Include="Common\AppResourceProvider.cpp">
<Filter>Common</Filter>
</ClCompile>
@ -56,12 +49,18 @@
<ClCompile Include="Common\NetworkManager.cpp">
<Filter>Common</Filter>
</ClCompile>
<ClCompile Include="Common\RadixType.cpp">
<Filter>Common</Filter>
</ClCompile>
<ClCompile Include="Common\TraceLogger.cpp">
<Filter>Common</Filter>
</ClCompile>
<ClCompile Include="Common\Utils.cpp">
<Filter>Common</Filter>
</ClCompile>
<ClCompile Include="Common\Automation\NarratorAnnouncement.cpp">
<Filter>Common\Automation</Filter>
</ClCompile>
<ClCompile Include="Common\Automation\NarratorNotifier.cpp">
<Filter>Common\Automation</Filter>
</ClCompile>
@ -80,26 +79,25 @@
<ClCompile Include="GraphingCalculator\GraphingCalculatorViewModel.cpp">
<Filter>GraphingCalculator</Filter>
</ClCompile>
<ClCompile Include="Common\Automation\NarratorAnnouncement.cpp">
<Filter>Common\Automation</Filter>
</ClCompile>
<ClCompile Include="GraphingCalculator\GraphingSettingsViewModel.cpp">
<Filter>GraphingCalculator</Filter>
</ClCompile>
<ClCompile Include="ApplicationViewModel.cpp" />
<ClCompile Include="DateCalculatorViewModel.cpp" />
<ClCompile Include="HistoryItemViewModel.cpp" />
<ClCompile Include="HistoryViewModel.cpp" />
<ClCompile Include="MemoryItemViewModel.cpp" />
<ClCompile Include="StandardCalculatorViewModel.cpp" />
<ClCompile Include="UnitConverterViewModel.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="pch.h" />
<ClInclude Include="targetver.h" />
<ClInclude Include="ApplicationViewModel.h" />
<ClInclude Include="DateCalculatorViewModel.h" />
<ClInclude Include="HistoryItemViewModel.h" />
<ClInclude Include="HistoryViewModel.h" />
<ClInclude Include="MemoryItemViewModel.h" />
<ClInclude Include="StandardCalculatorViewModel.h" />
<ClInclude Include="UnitConverterViewModel.h" />
<ClInclude Include="Common\AppResourceProvider.h">
<Filter>Common</Filter>
</ClInclude>
<ClInclude Include="Common\BitLength.h">
<Filter>Common</Filter>
</ClInclude>
<ClInclude Include="Common\CalculatorButtonPressedEventArgs.h">
<Filter>Common</Filter>
</ClInclude>
@ -115,6 +113,9 @@
<ClInclude Include="Common\DateCalculator.h">
<Filter>Common</Filter>
</ClInclude>
<ClInclude Include="Common\DelegateCommand.h">
<Filter>Common</Filter>
</ClInclude>
<ClInclude Include="Common\DisplayExpressionToken.h">
<Filter>Common</Filter>
</ClInclude>
@ -145,12 +146,21 @@
<ClInclude Include="Common\NetworkManager.h">
<Filter>Common</Filter>
</ClInclude>
<ClInclude Include="Common\NumberBase.h">
<Filter>Common</Filter>
</ClInclude>
<ClInclude Include="Common\RadixType.h">
<Filter>Common</Filter>
</ClInclude>
<ClInclude Include="Common\TraceLogger.h">
<Filter>Common</Filter>
</ClInclude>
<ClInclude Include="Common\Utils.h">
<Filter>Common</Filter>
</ClInclude>
<ClInclude Include="Common\Automation\NarratorAnnouncement.h">
<Filter>Common\Automation</Filter>
</ClInclude>
<ClInclude Include="Common\Automation\NarratorNotifier.h">
<Filter>Common\Automation</Filter>
</ClInclude>
@ -160,6 +170,9 @@
<ClInclude Include="DataLoaders\CurrencyHttpClient.h">
<Filter>DataLoaders</Filter>
</ClInclude>
<ClInclude Include="DataLoaders\DataLoaderMockConstants.h">
<Filter>DataLoaders</Filter>
</ClInclude>
<ClInclude Include="DataLoaders\ICurrencyHttpClient.h">
<Filter>DataLoaders</Filter>
</ClInclude>
@ -169,36 +182,27 @@
<ClInclude Include="DataLoaders\UnitConverterDataLoader.h">
<Filter>DataLoaders</Filter>
</ClInclude>
<ClInclude Include="DataLoaders\DataLoaderMockConstants.h">
<Filter>DataLoaders</Filter>
</ClInclude>
<ClInclude Include="Common\Automation\NarratorAnnouncement.h">
<Filter>Common\Automation</Filter>
</ClInclude>
<ClInclude Include="Common\BitLength.h">
<Filter>Common</Filter>
</ClInclude>
<ClInclude Include="Common\NumberBase.h">
<Filter>Common</Filter>
</ClInclude>
<ClInclude Include="GraphingCalculator\EquationViewModel.h">
<Filter>GraphingCalculator</Filter>
</ClInclude>
<ClInclude Include="GraphingCalculator\GraphingCalculatorViewModel.h">
<Filter>GraphingCalculator</Filter>
</ClInclude>
<ClInclude Include="GraphingCalculatorEnums.h">
<Filter>Common</Filter>
<ClInclude Include="GraphingCalculator\GraphingSettingsViewModel.h">
<Filter>GraphingCalculator</Filter>
</ClInclude>
<ClInclude Include="GraphingCalculator\VariableViewModel.h">
<Filter>GraphingCalculator</Filter>
</ClInclude>
<ClInclude Include="GraphingCalculator\GraphingSettingsViewModel.h">
<Filter>GraphingCalculator</Filter>
</ClInclude>
<ClInclude Include="Common\DelegateCommand.h">
<Filter>Common</Filter>
</ClInclude>
<ClInclude Include="ApplicationViewModel.h" />
<ClInclude Include="DateCalculatorViewModel.h" />
<ClInclude Include="GraphingCalculatorEnums.h" />
<ClInclude Include="HistoryItemViewModel.h" />
<ClInclude Include="HistoryViewModel.h" />
<ClInclude Include="MemoryItemViewModel.h" />
<ClInclude Include="StandardCalculatorViewModel.h" />
<ClInclude Include="targetver.h" />
<ClInclude Include="UnitConverterViewModel.h" />
</ItemGroup>
<ItemGroup>
<None Include="DataLoaders\DefaultFromToCurrency.json">
@ -206,6 +210,6 @@
</None>
</ItemGroup>
<ItemGroup>
<Page Include="$(MSBuildThisFileDirectory)DensityStyles\Compact.xaml" />
<ResourceCompile Include="CalcViewModel.rc" />
</ItemGroup>
</Project>

View file

@ -7,6 +7,7 @@
using namespace Platform;
using namespace Windows::ApplicationModel::Resources;
using namespace CalculatorApp;
using namespace CalculatorApp::ViewModel::Common;
AppResourceProvider::AppResourceProvider()
{

View file

@ -3,7 +3,7 @@
#pragma once
namespace CalculatorApp
namespace CalculatorApp::ViewModel::Common
{
public ref class AppResourceProvider sealed
{

View file

@ -9,7 +9,7 @@
// being used. Depending on the version of the OS the app is running on,
// the app may need a host that uses LiveRegionChanged or RaiseNotification.
namespace CalculatorApp::Common::Automation
namespace CalculatorApp::ViewModel::Common::Automation
{
public
interface class INarratorAnnouncementHost

View file

@ -4,7 +4,7 @@
#include "pch.h"
#include "LiveRegionHost.h"
using namespace CalculatorApp::Common::Automation;
using namespace CalculatorApp::ViewModel::Common::Automation;
using namespace Windows::UI::Xaml::Automation;
using namespace Windows::UI::Xaml::Automation::Peers;
using namespace Windows::UI::Xaml::Controls;

View file

@ -9,7 +9,7 @@
// This event is unreliable and should be deprecated in favor of the new
// RaiseNotification API in RS3.
namespace CalculatorApp::Common::Automation
namespace CalculatorApp::ViewModel::Common::Automation
{
// This class exists so that the app can run on RS2 and use LiveRegions
// to host notifications on those builds.

View file

@ -4,11 +4,11 @@
#include "pch.h"
#include "NarratorAnnouncement.h"
using namespace CalculatorApp::Common::Automation;
using namespace CalculatorApp::ViewModel::Common::Automation;
using namespace Platform;
using namespace Windows::UI::Xaml::Automation::Peers;
namespace CalculatorApp::Common::Automation
namespace CalculatorApp::ViewModel::Common::Automation
{
namespace CalculatorActivityIds
{
@ -30,6 +30,7 @@ namespace CalculatorApp::Common::Automation
StringReference GraphViewBestFitChanged(L"GraphViewBestFitChanged");
StringReference AlwaysOnTop(L"AlwaysOnTop");
StringReference BitShiftRadioButtonContent(L"BitShiftRadioButtonContent");
StringReference SettingsPageOpened(L"SettingsPageOpened");
}
}
@ -204,3 +205,12 @@ NarratorAnnouncement ^ CalculatorAnnouncement::GetBitShiftRadioButtonCheckedAnno
AutomationNotificationKind::ActionCompleted,
AutomationNotificationProcessing::ImportantMostRecent);
}
NarratorAnnouncement ^ CalculatorAnnouncement::GetSettingsPageOpenedAnnouncement(Platform::String ^ announcement)
{
return ref new NarratorAnnouncement(
announcement,
CalculatorActivityIds::SettingsPageOpened,
AutomationNotificationKind::ActionCompleted,
AutomationNotificationProcessing::ImportantMostRecent);
}

View file

@ -3,7 +3,7 @@
#pragma once
namespace CalculatorApp::Common::Automation
namespace CalculatorApp::ViewModel::Common::Automation
{
public
ref class NarratorAnnouncement sealed
@ -28,25 +28,23 @@ public
static bool IsValid(NarratorAnnouncement ^ announcement);
private:
// Make CalculatorAnnouncement a friend class so it is the only
// class that can access the private constructor.
friend class CalculatorAnnouncement;
Platform::String ^ m_announcement;
Platform::String ^ m_activityId;
Windows::UI::Xaml::Automation::Peers::AutomationNotificationKind m_kind;
Windows::UI::Xaml::Automation::Peers::AutomationNotificationProcessing m_processing;
internal:
NarratorAnnouncement(
Platform::String ^ announcement,
Platform::String ^ activityId,
Windows::UI::Xaml::Automation::Peers::AutomationNotificationKind kind,
Windows::UI::Xaml::Automation::Peers::AutomationNotificationProcessing processing);
Platform::String ^ m_announcement;
Platform::String ^ m_activityId;
Windows::UI::Xaml::Automation::Peers::AutomationNotificationKind m_kind;
Windows::UI::Xaml::Automation::Peers::AutomationNotificationProcessing m_processing;
};
// CalculatorAnnouncement is intended to contain only static methods
// that return announcements made for the Calculator app.
class CalculatorAnnouncement
public
ref class CalculatorAnnouncement sealed
{
public:
static NarratorAnnouncement ^ GetDisplayUpdatedAnnouncement(Platform::String ^ announcement);
@ -77,5 +75,7 @@ public
static NarratorAnnouncement ^ GetAlwaysOnTopChangedAnnouncement(Platform::String ^ announcement);
static NarratorAnnouncement ^ GetBitShiftRadioButtonCheckedAnnouncement(Platform::String ^ announcement);
static NarratorAnnouncement ^ GetSettingsPageOpenedAnnouncement(Platform::String ^ announcement);
};
}

View file

@ -6,7 +6,7 @@
#include "NotificationHost.h"
#include "LiveRegionHost.h"
using namespace CalculatorApp::Common::Automation;
using namespace CalculatorApp::ViewModel::Common::Automation;
using namespace std;
INarratorAnnouncementHost ^ NarratorAnnouncementHostFactory::s_hostProducer;

View file

@ -9,7 +9,7 @@
// Depending on the version of the OS the app is running on, the factory will return
// an announcement host appropriate for that version.
namespace CalculatorApp::Common::Automation
namespace CalculatorApp::ViewModel::Common::Automation
{
class NarratorAnnouncementHostFactory
{

View file

@ -6,7 +6,7 @@
#include "pch.h"
#include "NarratorNotifier.h"
using namespace CalculatorApp::Common::Automation;
using namespace CalculatorApp::ViewModel::Common::Automation;
using namespace Platform;
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Automation;

View file

@ -6,7 +6,7 @@
#pragma once
#include "NarratorAnnouncement.h"
namespace CalculatorApp::Common::Automation
namespace CalculatorApp::ViewModel::Common::Automation
{
public
ref class NarratorNotifier sealed : public Windows::UI::Xaml::DependencyObject

View file

@ -4,7 +4,7 @@
#include "pch.h"
#include "NotificationHost.h"
using namespace CalculatorApp::Common::Automation;
using namespace CalculatorApp::ViewModel::Common::Automation;
using namespace Windows::Foundation::Metadata;
using namespace Windows::UI::Xaml::Automation;
using namespace Windows::UI::Xaml::Automation::Peers;

View file

@ -8,7 +8,7 @@
// This class announces NarratorAnnouncements using the RaiseNotification API
// available in RS3.
namespace CalculatorApp::Common::Automation
namespace CalculatorApp::ViewModel::Common::Automation
{
public
ref class NotificationHost sealed : public INarratorAnnouncementHost
@ -23,10 +23,10 @@ public
private:
static Windows::UI::Xaml::Automation::Peers::AutomationNotificationKind
GetWindowsNotificationKind(CalculatorApp::Common::Automation::AutomationNotificationKind customKindType);
GetWindowsNotificationKind(CalculatorApp::ViewModel::Common::Automation::AutomationNotificationKind customKindType);
static Windows::UI::Xaml::Automation::Peers::AutomationNotificationProcessing
GetWindowsNotificationProcessing(CalculatorApp::Common::Automation::AutomationNotificationProcessing customProcessingType);
GetWindowsNotificationProcessing(CalculatorApp::ViewModel::Common::Automation::AutomationNotificationProcessing customProcessingType);
private:
Windows::UI::Xaml::UIElement ^ m_host;

View file

@ -1,6 +1,6 @@
#pragma once
namespace CalculatorApp
namespace CalculatorApp::ViewModel
{
namespace Common
{

View file

@ -5,7 +5,8 @@
#include "CalculatorButtonPressedEventArgs.h"
using namespace CalculatorApp;
using namespace CalculatorApp::Common;
using namespace CalculatorApp::ViewModel;
using namespace CalculatorApp::ViewModel::Common;
using namespace Platform;
NumbersAndOperatorsEnum CalculatorButtonPressedEventArgs::GetOperationFromCommandParameter(_In_ Object ^ commandParameter)

View file

@ -6,7 +6,7 @@
#include "CalculatorButtonUser.h"
#include "Utils.h"
namespace CalculatorApp
namespace CalculatorApp::ViewModel
{
namespace Common
{
@ -15,15 +15,15 @@ namespace CalculatorApp
{
public:
PROPERTY_R(Platform::String ^, AuditoryFeedback);
PROPERTY_R(CalculatorApp::NumbersAndOperatorsEnum, Operation);
PROPERTY_R(CalculatorApp::ViewModel::Common::NumbersAndOperatorsEnum, Operation);
CalculatorButtonPressedEventArgs(Platform::String ^ feedback, CalculatorApp::NumbersAndOperatorsEnum operation)
CalculatorButtonPressedEventArgs(Platform::String ^ feedback, CalculatorApp::ViewModel::Common::NumbersAndOperatorsEnum operation)
: m_AuditoryFeedback(feedback)
, m_Operation(operation)
{
}
static CalculatorApp::NumbersAndOperatorsEnum GetOperationFromCommandParameter(_In_ Platform::Object ^ commandParameter);
static CalculatorApp::ViewModel::Common::NumbersAndOperatorsEnum GetOperationFromCommandParameter(_In_ Platform::Object ^ commandParameter);
static Platform::String ^ GetAuditoryFeedbackFromCommandParameter(_In_ Platform::Object ^ commandParameter);
};
}

View file

@ -5,12 +5,11 @@
#include "CalcManager/Command.h"
namespace CalculatorApp
namespace CalculatorApp::ViewModel::Common
{
namespace CM = CalculationManager;
public
enum class NumbersAndOperatorsEnum
public enum class NumbersAndOperatorsEnum
{
Zero = (int)CM::Command::Command0,
One = (int)CM::Command::Command1,

View file

@ -8,143 +8,149 @@
#include "StandardCalculatorViewModel.h"
using namespace CalculatorApp;
using namespace CalculatorApp::ViewModel;
using namespace CalculatorApp::ViewModel::Common;
using namespace CalculationManager;
using namespace Platform;
using namespace std;
CalculatorDisplay::CalculatorDisplay()
namespace CalculatorApp::ViewModel::Common
{
}
void CalculatorDisplay::SetCallback(Platform::WeakReference callbackReference)
{
m_callbackReference = callbackReference;
}
void CalculatorDisplay::SetHistoryCallback(Platform::WeakReference callbackReference)
{
m_historyCallbackReference = callbackReference;
}
void CalculatorDisplay::SetPrimaryDisplay(_In_ const wstring& displayStringValue, _In_ bool isError)
{
if (m_callbackReference)
CalculatorDisplay::CalculatorDisplay()
{
if (auto calcVM = m_callbackReference.Resolve<ViewModel::StandardCalculatorViewModel>())
}
void CalculatorDisplay::SetCallback(Platform::WeakReference callbackReference)
{
m_callbackReference = callbackReference;
}
void CalculatorDisplay::SetHistoryCallback(Platform::WeakReference callbackReference)
{
m_historyCallbackReference = callbackReference;
}
void CalculatorDisplay::SetPrimaryDisplay(_In_ const wstring& displayStringValue, _In_ bool isError)
{
if (m_callbackReference)
{
calcVM->SetPrimaryDisplay(StringReference(displayStringValue.c_str()), isError);
if (auto calcVM = m_callbackReference.Resolve<ViewModel::StandardCalculatorViewModel>())
{
calcVM->SetPrimaryDisplay(StringReference(displayStringValue.c_str()), isError);
}
}
}
void CalculatorDisplay::SetParenthesisNumber(_In_ unsigned int parenthesisCount)
{
if (m_callbackReference != nullptr)
{
if (auto calcVM = m_callbackReference.Resolve<ViewModel::StandardCalculatorViewModel>())
{
calcVM->SetParenthesisCount(parenthesisCount);
}
}
}
void CalculatorDisplay::OnNoRightParenAdded()
{
if (m_callbackReference != nullptr)
{
if (auto calcVM = m_callbackReference.Resolve<ViewModel::StandardCalculatorViewModel>())
{
calcVM->OnNoRightParenAdded();
}
}
}
void CalculatorDisplay::SetIsInError(bool isError)
{
if (m_callbackReference != nullptr)
{
if (auto calcVM = m_callbackReference.Resolve<ViewModel::StandardCalculatorViewModel>())
{
calcVM->IsInError = isError;
}
}
}
void CalculatorDisplay::SetExpressionDisplay(
_Inout_ std::shared_ptr<std::vector<std::pair<std::wstring, int>>> const& tokens,
_Inout_ std::shared_ptr<std::vector<std::shared_ptr<IExpressionCommand>>> const& commands)
{
if (m_callbackReference != nullptr)
{
if (auto calcVM = m_callbackReference.Resolve<ViewModel::StandardCalculatorViewModel>())
{
calcVM->SetExpressionDisplay(tokens, commands);
}
}
}
void CalculatorDisplay::SetMemorizedNumbers(_In_ const vector<std::wstring>& newMemorizedNumbers)
{
if (m_callbackReference != nullptr)
{
if (auto calcVM = m_callbackReference.Resolve<ViewModel::StandardCalculatorViewModel>())
{
calcVM->SetMemorizedNumbers(newMemorizedNumbers);
}
}
}
void CalculatorDisplay::OnHistoryItemAdded(_In_ unsigned int addedItemIndex)
{
if (m_historyCallbackReference != nullptr)
{
if (auto historyVM = m_historyCallbackReference.Resolve<ViewModel::HistoryViewModel>())
{
historyVM->OnHistoryItemAdded(addedItemIndex);
}
}
}
void CalculatorDisplay::MaxDigitsReached()
{
if (m_callbackReference != nullptr)
{
if (auto calcVM = m_callbackReference.Resolve<ViewModel::StandardCalculatorViewModel>())
{
calcVM->OnMaxDigitsReached();
}
}
}
void CalculatorDisplay::BinaryOperatorReceived()
{
if (m_callbackReference != nullptr)
{
if (auto calcVM = m_callbackReference.Resolve<ViewModel::StandardCalculatorViewModel>())
{
calcVM->OnBinaryOperatorReceived();
}
}
}
void CalculatorDisplay::MemoryItemChanged(unsigned int indexOfMemory)
{
if (m_callbackReference != nullptr)
{
if (auto calcVM = m_callbackReference.Resolve<ViewModel::StandardCalculatorViewModel>())
{
calcVM->OnMemoryItemChanged(indexOfMemory);
}
}
}
void CalculatorDisplay::InputChanged()
{
if (m_callbackReference != nullptr)
{
if (auto calcVM = m_callbackReference.Resolve<ViewModel::StandardCalculatorViewModel>())
{
calcVM->OnInputChanged();
}
}
}
}
void CalculatorDisplay::SetParenthesisNumber(_In_ unsigned int parenthesisCount)
{
if (m_callbackReference != nullptr)
{
if (auto calcVM = m_callbackReference.Resolve<ViewModel::StandardCalculatorViewModel>())
{
calcVM->SetParenthesisCount(parenthesisCount);
}
}
}
void CalculatorDisplay::OnNoRightParenAdded()
{
if (m_callbackReference != nullptr)
{
if (auto calcVM = m_callbackReference.Resolve<ViewModel::StandardCalculatorViewModel>())
{
calcVM->OnNoRightParenAdded();
}
}
}
void CalculatorDisplay::SetIsInError(bool isError)
{
if (m_callbackReference != nullptr)
{
if (auto calcVM = m_callbackReference.Resolve<ViewModel::StandardCalculatorViewModel>())
{
calcVM->IsInError = isError;
}
}
}
void CalculatorDisplay::SetExpressionDisplay(
_Inout_ std::shared_ptr<std::vector<std::pair<std::wstring, int>>> const& tokens,
_Inout_ std::shared_ptr<std::vector<std::shared_ptr<IExpressionCommand>>> const& commands)
{
if (m_callbackReference != nullptr)
{
if (auto calcVM = m_callbackReference.Resolve<ViewModel::StandardCalculatorViewModel>())
{
calcVM->SetExpressionDisplay(tokens, commands);
}
}
}
void CalculatorDisplay::SetMemorizedNumbers(_In_ const vector<std::wstring>& newMemorizedNumbers)
{
if (m_callbackReference != nullptr)
{
if (auto calcVM = m_callbackReference.Resolve<ViewModel::StandardCalculatorViewModel>())
{
calcVM->SetMemorizedNumbers(newMemorizedNumbers);
}
}
}
void CalculatorDisplay::OnHistoryItemAdded(_In_ unsigned int addedItemIndex)
{
if (m_historyCallbackReference != nullptr)
{
if (auto historyVM = m_historyCallbackReference.Resolve<ViewModel::HistoryViewModel>())
{
historyVM->OnHistoryItemAdded(addedItemIndex);
}
}
}
void CalculatorDisplay::MaxDigitsReached()
{
if (m_callbackReference != nullptr)
{
if (auto calcVM = m_callbackReference.Resolve<ViewModel::StandardCalculatorViewModel>())
{
calcVM->OnMaxDigitsReached();
}
}
}
void CalculatorDisplay::BinaryOperatorReceived()
{
if (m_callbackReference != nullptr)
{
if (auto calcVM = m_callbackReference.Resolve<ViewModel::StandardCalculatorViewModel>())
{
calcVM->OnBinaryOperatorReceived();
}
}
}
void CalculatorDisplay::MemoryItemChanged(unsigned int indexOfMemory)
{
if (m_callbackReference != nullptr)
{
if (auto calcVM = m_callbackReference.Resolve<ViewModel::StandardCalculatorViewModel>())
{
calcVM->OnMemoryItemChanged(indexOfMemory);
}
}
}
void CalculatorDisplay::InputChanged()
{
if (m_callbackReference != nullptr)
{
if (auto calcVM = m_callbackReference.Resolve<ViewModel::StandardCalculatorViewModel>())
{
calcVM->OnInputChanged();
}
}
}

View file

@ -5,7 +5,7 @@
#include "CalcManager/Header Files/ICalcDisplay.h"
namespace CalculatorApp
namespace CalculatorApp::ViewModel::Common
{
// Callback interface to be implemented by the CalculatorManager
class CalculatorDisplay : public ICalcDisplay

View file

@ -9,7 +9,8 @@
using namespace std;
using namespace concurrency;
using namespace CalculatorApp;
using namespace CalculatorApp::Common;
using namespace CalculatorApp::ViewModel::Common;
using namespace CalculatorApp::ViewModel;
using namespace Platform;
using namespace Platform::Collections;
using namespace Windows::Foundation;
@ -96,7 +97,7 @@ bool CopyPasteManager::HasStringToPaste()
String ^ CopyPasteManager::ValidatePasteExpression(String ^ pastedText, ViewMode mode, NumberBase programmerNumberBase, BitLength bitLengthType)
{
return ValidatePasteExpression(pastedText, mode, NavCategory::GetGroupType(mode), programmerNumberBase, bitLengthType);
return ValidatePasteExpression(pastedText, mode, NavCategoryStates::GetGroupType(mode), programmerNumberBase, bitLengthType);
}
// return "NoOp" if pastedText is invalid else return pastedText
@ -116,7 +117,7 @@ String
}
// Get english translated expression
String ^ englishString = LocalizationSettings::GetInstance().GetEnglishValueFromLocalizedDigits(pastedText);
String ^ englishString = LocalizationSettings::GetInstance()->GetEnglishValueFromLocalizedDigits(pastedText);
// Removing the spaces, comma separator from the pasteExpression to allow pasting of expressions like 1 + 2+1,333
auto pasteExpression = wstring(RemoveUnwantedCharsFromString(englishString)->Data());
@ -287,9 +288,8 @@ bool CopyPasteManager::ExpressionRegExMatch(
}
else if (mode == ViewMode::Programmer)
{
patterns.assign(
programmerModePatterns[(int)programmerNumberBase - (int)NumberBase::HexBase].begin(),
programmerModePatterns[(int)programmerNumberBase - (int)NumberBase::HexBase].end());
auto pattern = &programmerModePatterns[static_cast<int>(programmerNumberBase) - static_cast<int>(NumberBase::HexBase)];
patterns.assign(pattern->begin(), pattern->end());
}
else if (modeType == CategoryGroupType::Converter)
{
@ -504,18 +504,15 @@ ULONG32 CopyPasteManager::StandardScientificOperandLength(Platform::String ^ ope
const bool hasDecimal = operandWstring.find('.') != wstring::npos;
auto length = operandWstring.length();
if (hasDecimal)
if (hasDecimal && length >= 2)
{
if (length >= 2)
if ((operandWstring[0] == L'0') && (operandWstring[1] == L'.'))
{
if ((operandWstring[0] == L'0') && (operandWstring[1] == L'.'))
{
length -= 2;
}
else
{
length -= 1;
}
length -= 2;
}
else
{
length -= 1;
}
}
@ -614,7 +611,7 @@ ULONG32 CopyPasteManager::ProgrammerOperandLength(Platform::String ^ operand, Nu
Platform::String ^ CopyPasteManager::RemoveUnwantedCharsFromString(Platform::String ^ input)
{
constexpr wchar_t unWantedChars[] = { L' ', L',', L'"', 165, 164, 8373, 36, 8353, 8361, 8362, 8358, 8377, 163, 8364, 8234, 8235, 8236, 8237, 160 };
input = CalculatorApp::Common::LocalizationSettings::GetInstance().RemoveGroupSeparators(input);
input = CalculatorApp::ViewModel::Common::LocalizationSettings::GetInstance()->RemoveGroupSeparators(input);
return ref new String(Utils::RemoveUnwantedCharsFromString(input->Data(), unWantedChars).c_str());
}

View file

@ -13,10 +13,9 @@ namespace CalculatorUnitTests
class CopyPasteManagerTest;
}
namespace CalculatorApp
namespace CalculatorApp::ViewModel::Common
{
public
value struct CopyPasteMaxOperandLengthAndValue
public value struct CopyPasteMaxOperandLengthAndValue
{
unsigned int maxLength;
unsigned long long maxValue;
@ -26,9 +25,11 @@ public
{
public:
static void CopyToClipboard(Platform::String ^ stringToCopy);
static Windows::Foundation::IAsyncOperation<
Platform::String
^> ^ GetStringToPaste(CalculatorApp::Common::ViewMode mode, CalculatorApp::Common::CategoryGroupType modeType, CalculatorApp::Common::NumberBase programmerNumberBase, CalculatorApp::Common::BitLength bitLengthType);
static Windows::Foundation::IAsyncOperation<Platform::String ^> ^ GetStringToPaste(
CalculatorApp::ViewModel::Common::ViewMode mode,
CalculatorApp::ViewModel::Common::CategoryGroupType modeType,
CalculatorApp::ViewModel::Common::NumberBase programmerNumberBase,
CalculatorApp::ViewModel::Common::BitLength bitLengthType);
static bool HasStringToPaste();
static bool IsErrorMessage(Platform::String ^ message);
static property unsigned int MaxPasteableLength
@ -87,39 +88,39 @@ public
static Platform::String
^ ValidatePasteExpression(
Platform::String ^ pastedText,
CalculatorApp::Common::ViewMode mode,
CalculatorApp::Common::NumberBase programmerNumberBase,
CalculatorApp::Common::BitLength bitLengthType);
CalculatorApp::ViewModel::Common::ViewMode mode,
CalculatorApp::ViewModel::Common::NumberBase programmerNumberBase,
CalculatorApp::ViewModel::Common::BitLength bitLengthType);
static Platform::String
^ ValidatePasteExpression(
Platform::String ^ pastedText,
CalculatorApp::Common::ViewMode mode,
CalculatorApp::Common::CategoryGroupType modeType,
CalculatorApp::Common::NumberBase programmerNumberBase,
CalculatorApp::Common::BitLength bitLengthType);
CalculatorApp::ViewModel::Common::ViewMode mode,
CalculatorApp::ViewModel::Common::CategoryGroupType modeType,
CalculatorApp::ViewModel::Common::NumberBase programmerNumberBase,
CalculatorApp::ViewModel::Common::BitLength bitLengthType);
static CopyPasteMaxOperandLengthAndValue GetMaxOperandLengthAndValue(
CalculatorApp::Common::ViewMode mode,
CalculatorApp::Common::CategoryGroupType modeType,
CalculatorApp::Common::NumberBase programmerNumberBase,
CalculatorApp::Common::BitLength bitLengthType);
CalculatorApp::ViewModel::Common::ViewMode mode,
CalculatorApp::ViewModel::Common::CategoryGroupType modeType,
CalculatorApp::ViewModel::Common::NumberBase programmerNumberBase,
CalculatorApp::ViewModel::Common::BitLength bitLengthType);
static Windows::Foundation::Collections::IVector<
Platform::String ^> ^ ExtractOperands(Platform::String ^ pasteExpression, CalculatorApp::Common::ViewMode mode);
Platform::String ^> ^ ExtractOperands(Platform::String ^ pasteExpression, CalculatorApp::ViewModel::Common::ViewMode mode);
static bool ExpressionRegExMatch(
Windows::Foundation::Collections::IVector<Platform::String ^> ^ operands,
CalculatorApp::Common::ViewMode mode,
CalculatorApp::Common::CategoryGroupType modeType,
CalculatorApp::Common::NumberBase programmerNumberBase,
CalculatorApp::Common::BitLength bitLengthType);
CalculatorApp::ViewModel::Common::ViewMode mode,
CalculatorApp::ViewModel::Common::CategoryGroupType modeType,
CalculatorApp::ViewModel::Common::NumberBase programmerNumberBase,
CalculatorApp::ViewModel::Common::BitLength bitLengthType);
static Platform::String ^ SanitizeOperand(Platform::String ^ operand);
static Platform::String ^ RemoveUnwantedCharsFromString(Platform::String ^ input);
static Platform::IBox<unsigned long long int> ^ TryOperandToULL(Platform::String ^ operand, CalculatorApp::Common::NumberBase numberBase);
static Platform::IBox<unsigned long long int> ^ TryOperandToULL(Platform::String ^ operand, CalculatorApp::ViewModel::Common::NumberBase numberBase);
static ULONG32 StandardScientificOperandLength(Platform::String ^ operand);
static ULONG32 OperandLength(
Platform::String ^ operand,
CalculatorApp::Common::ViewMode mode,
CalculatorApp::Common::CategoryGroupType modeType,
CalculatorApp::Common::NumberBase programmerNumberBase);
static ULONG32 ProgrammerOperandLength(Platform::String ^ operand, CalculatorApp::Common::NumberBase numberBase);
CalculatorApp::ViewModel::Common::ViewMode mode,
CalculatorApp::ViewModel::Common::CategoryGroupType modeType,
CalculatorApp::ViewModel::Common::NumberBase programmerNumberBase);
static ULONG32 ProgrammerOperandLength(Platform::String ^ operand, CalculatorApp::ViewModel::Common::NumberBase numberBase);
private:
static constexpr size_t MaxStandardOperandLengthValue = 16;

View file

@ -7,7 +7,7 @@
using namespace Platform;
using namespace Windows::Foundation;
using namespace Windows::Globalization;
using namespace CalculatorApp::Common::DateCalculation;
using namespace CalculatorApp::ViewModel::Common::DateCalculation;
bool operator==(const DateDifference& l, const DateDifference& r)
{

View file

@ -13,7 +13,7 @@ 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;
namespace CalculatorApp
namespace CalculatorApp::ViewModel
{
namespace Common
{
@ -68,4 +68,4 @@ namespace CalculatorApp
}
}
bool operator==(const CalculatorApp::Common::DateCalculation::DateDifference& l, const CalculatorApp::Common::DateCalculation::DateDifference& r);
bool operator==(const CalculatorApp::ViewModel::Common::DateCalculation::DateDifference& l, const CalculatorApp::ViewModel::Common::DateCalculation::DateDifference& r);

View file

@ -3,22 +3,18 @@
#pragma once
namespace CalculatorApp
namespace CalculatorApp::ViewModel
{
namespace Common
{
template <typename TTarget>
ref class DelegateCommand : public Windows::UI::Xaml::Input::ICommand
public delegate void DelegateCommandHandler(Platform::Object ^ parameter);
public ref class DelegateCommand sealed : public Windows::UI::Xaml::Input::ICommand
{
internal :
typedef void (TTarget::*CommandHandlerFunc)(Platform::Object ^);
DelegateCommand(TTarget ^ target, CommandHandlerFunc func)
: m_weakTarget(target)
, m_function(func)
{
}
public:
DelegateCommand(DelegateCommandHandler ^ handler)
: m_handler(handler)
{}
private:
// Explicit, and private, implementation of ICommand, this way of programming makes it so
@ -27,11 +23,7 @@ namespace CalculatorApp
// code in the app calling Execute.
virtual void ExecuteImpl(Platform::Object ^ parameter) sealed = Windows::UI::Xaml::Input::ICommand::Execute
{
TTarget ^ target = m_weakTarget.Resolve<TTarget>();
if (target)
{
(target->*m_function)(parameter);
}
m_handler->Invoke(parameter);
}
virtual bool CanExecuteImpl(Platform::Object ^ parameter) sealed = Windows::UI::Xaml::Input::ICommand::CanExecute
@ -39,9 +31,9 @@ namespace CalculatorApp
return true;
}
virtual event Windows::Foundation::EventHandler<Platform::Object^>^ CanExecuteChangedImpl
virtual event Windows::Foundation::EventHandler<Platform::Object ^> ^ CanExecuteChangedImpl
{
virtual Windows::Foundation::EventRegistrationToken add(Windows::Foundation::EventHandler<Platform::Object^>^ handler) sealed = Windows::UI::Xaml::Input::ICommand::CanExecuteChanged::add
virtual Windows::Foundation::EventRegistrationToken add(Windows::Foundation::EventHandler<Platform::Object ^> ^ handler) sealed = Windows::UI::Xaml::Input::ICommand::CanExecuteChanged::add
{
return m_canExecuteChanged += handler;
}
@ -52,17 +44,25 @@ namespace CalculatorApp
}
private:
DelegateCommandHandler ^ m_handler;
event Windows::Foundation::EventHandler<Platform::Object^>^ m_canExecuteChanged;
CommandHandlerFunc m_function;
Platform::WeakReference m_weakTarget;
event Windows::Foundation::EventHandler<Platform::Object ^> ^ m_canExecuteChanged;
};
template <typename TTarget, typename TFuncPtr>
DelegateCommand<TTarget> ^ MakeDelegate(TTarget ^ target, TFuncPtr&& function) {
return ref new DelegateCommand<TTarget>(target, std::forward<TFuncPtr>(function));
}
DelegateCommandHandler ^ MakeDelegateCommandHandler(TTarget ^ target, TFuncPtr&& function)
{
Platform::WeakReference weakTarget(target);
return ref new DelegateCommandHandler([weakTarget, function=std::forward<TFuncPtr>(function)](Platform::Object ^ param)
{
TTarget ^ thatTarget = weakTarget.Resolve<TTarget>();
if (nullptr != thatTarget)
{
(thatTarget->*function)(param);
}
}
);
}
}
}

View file

@ -5,7 +5,7 @@
#include "Utils.h"
namespace CalculatorApp::Common
namespace CalculatorApp::ViewModel::Common
{
public
enum class TokenType
@ -33,6 +33,7 @@ public
OBSERVABLE_PROPERTY_RW(int, TokenPosition);
OBSERVABLE_PROPERTY_RW(bool, IsTokenEditable);
OBSERVABLE_PROPERTY_RW(int, CommandIndex);
OBSERVABLE_PROPERTY_RW(TokenType, Type);
OBSERVABLE_PROPERTY_R(Platform::String ^, OriginalToken);
property bool IsTokenInEditMode
@ -50,7 +51,6 @@ public
m_InEditMode = val;
}
}
internal : OBSERVABLE_PROPERTY_RW(TokenType, Type);
private:
bool m_InEditMode;

View file

@ -5,7 +5,7 @@
#include "EngineResourceProvider.h"
#include "Common/LocalizationSettings.h"
using namespace CalculatorApp::Common;
using namespace CalculatorApp::ViewModel::Common;
using namespace Platform;
using namespace Windows::ApplicationModel::Resources;
using namespace std;
@ -19,16 +19,16 @@ namespace CalculatorApp
wstring EngineResourceProvider::GetCEngineString(wstring_view id)
{
const auto& localizationSettings = LocalizationSettings::GetInstance();
LocalizationSettings^ localizationSettings = LocalizationSettings::GetInstance();
if (id.compare(L"sDecimal") == 0)
{
return localizationSettings.GetDecimalSeparatorStr();
return localizationSettings->GetDecimalSeparatorStr();
}
if (id.compare(L"sThousand") == 0)
{
return localizationSettings.GetNumberGroupingSeparatorStr();
return localizationSettings->GetNumberGroupingSeparatorStr();
}
if (id.compare(L"sGrouping") == 0)
@ -39,7 +39,7 @@ namespace CalculatorApp
// 3;2;0 0x023 - group 1st 3 and then every 2 digits
// 4;0 0x004 - group every 4 digits
// 5;3;2;0 0x235 - group 5, then 3, then every 2
wstring numberGroupingString = localizationSettings.GetNumberGroupingStr();
wstring numberGroupingString = localizationSettings->GetNumberGroupingStr();
return numberGroupingString;
}

View file

@ -5,7 +5,7 @@
#include "CalcManager/CalculatorResource.h"
namespace CalculatorApp
namespace CalculatorApp::ViewModel::Common
{
class EngineResourceProvider : public CalculationManager::IResourceProvider
{

View file

@ -4,7 +4,7 @@
#include "pch.h"
#include "ExpressionCommandDeserializer.h"
using namespace CalculatorApp::Common;
using namespace CalculatorApp::ViewModel::Common;
using namespace Windows::Storage::Streams;
CommandDeserializer::CommandDeserializer(_In_ DataReader ^ dataReader)
@ -17,24 +17,16 @@ std::shared_ptr<IExpressionCommand> CommandDeserializer::Deserialize(_In_ Calcul
switch (cmdType)
{
case CalculationManager::CommandType::OperandCommand:
return std::make_shared<COpndCommand>(DeserializeOperand());
break;
case CalculationManager::CommandType::Parentheses:
return std::make_shared<CParentheses>(DeserializeParentheses());
break;
case CalculationManager::CommandType::UnaryCommand:
return std::make_shared<CUnaryCommand>(DeserializeUnary());
break;
case CalculationManager::CommandType::BinaryCommand:
return std::make_shared<CBinaryCommand>(DeserializeBinary());
break;
default:
throw ref new Platform::Exception(E_INVALIDARG, ref new Platform::String(L"Unknown command type"));

View file

@ -5,7 +5,7 @@
#include "CalcManager/ExpressionCommand.h"
namespace CalculatorApp
namespace CalculatorApp::ViewModel
{
namespace Common
{

View file

@ -4,7 +4,7 @@
#include "pch.h"
#include "Common/ExpressionCommandSerializer.h"
using namespace CalculatorApp::Common;
using namespace CalculatorApp::ViewModel::Common;
using namespace Windows::Storage::Streams;
SerializeCommandVisitor::SerializeCommandVisitor(_In_ DataWriter ^ dataWriter)

View file

@ -5,7 +5,7 @@
#include "CalcManager/ExpressionCommand.h"
namespace CalculatorApp
namespace CalculatorApp::ViewModel
{
namespace Common
{

View file

@ -6,8 +6,9 @@
#include "LocalizationSettings.h"
#include "AppResourceProvider.h"
using namespace CalculatorApp::Common;
using namespace CalculatorApp::Common::LocalizationServiceProperties;
using namespace CalculatorApp::ViewModel::Common;
using namespace CalculatorApp::ViewModel::Common::LocalizationServiceProperties;
using namespace CalculatorApp::ViewModel;
using namespace Concurrency;
using namespace Platform;
using namespace Platform::Collections;
@ -371,7 +372,7 @@ void LocalizationService::UpdateFontFamilyAndSize(DependencyObject ^ target)
// If successful, returns a formatter that respects the user's regional format settings,
// as configured by running intl.cpl.
DecimalFormatter ^ LocalizationService::GetRegionalSettingsAwareDecimalFormatter() const
DecimalFormatter ^ LocalizationService::GetRegionalSettingsAwareDecimalFormatter()
{
IIterable<String ^> ^ languageIdentifiers = LocalizationService::GetLanguageIdentifiers();
if (languageIdentifiers != nullptr)
@ -386,7 +387,7 @@ DecimalFormatter ^ LocalizationService::GetRegionalSettingsAwareDecimalFormatter
// as configured by running intl.cpl.
//
// This helper function creates a DateTimeFormatter with a TwentyFour hour clock
DateTimeFormatter ^ LocalizationService::GetRegionalSettingsAwareDateTimeFormatter(_In_ String ^ format) const
DateTimeFormatter ^ LocalizationService::GetRegionalSettingsAwareDateTimeFormatter(_In_ String ^ format)
{
IIterable<String ^> ^ languageIdentifiers = LocalizationService::GetLanguageIdentifiers();
if (languageIdentifiers == nullptr)
@ -399,7 +400,7 @@ DateTimeFormatter ^ LocalizationService::GetRegionalSettingsAwareDateTimeFormatt
// If successful, returns a formatter that respects the user's regional format settings,
// as configured by running intl.cpl.
DateTimeFormatter ^ LocalizationService::GetRegionalSettingsAwareDateTimeFormatter(_In_ String ^ format, _In_ String ^ calendarIdentifier, _In_ String ^ clockIdentifier) const
DateTimeFormatter ^ LocalizationService::GetRegionalSettingsAwareDateTimeFormatter(_In_ String ^ format, _In_ String ^ calendarIdentifier, _In_ String ^ clockIdentifier)
{
IIterable<String ^> ^ languageIdentifiers = LocalizationService::GetLanguageIdentifiers();
if (languageIdentifiers == nullptr)
@ -410,7 +411,7 @@ DateTimeFormatter ^ LocalizationService::GetRegionalSettingsAwareDateTimeFormatt
return ref new DateTimeFormatter(format, languageIdentifiers, GlobalizationPreferences::HomeGeographicRegion, calendarIdentifier, clockIdentifier);
}
CurrencyFormatter ^ LocalizationService::GetRegionalSettingsAwareCurrencyFormatter() const
CurrencyFormatter ^ LocalizationService::GetRegionalSettingsAwareCurrencyFormatter()
{
String ^ userCurrency =
(GlobalizationPreferences::Currencies->Size > 0) ? GlobalizationPreferences::Currencies->GetAt(0) : StringReference(DefaultCurrencyCode.data());
@ -423,7 +424,7 @@ CurrencyFormatter ^ LocalizationService::GetRegionalSettingsAwareCurrencyFormatt
auto currencyFormatter = ref new CurrencyFormatter(userCurrency, languageIdentifiers, GlobalizationPreferences::HomeGeographicRegion);
int fractionDigits = LocalizationSettings::GetInstance().GetCurrencyTrailingDigits();
int fractionDigits = LocalizationSettings::GetInstance()->GetCurrencyTrailingDigits();
currencyFormatter->FractionDigits = fractionDigits;
return currencyFormatter;

View file

@ -5,7 +5,7 @@
#include "Utils.h"
namespace CalculatorApp
namespace CalculatorApp::ViewModel
{
namespace Common
{
@ -30,10 +30,7 @@ namespace CalculatorApp
DEPENDENCY_PROPERTY_ATTACHED_WITH_DEFAULT_AND_CALLBACK(LanguageFontType, FontType, LanguageFontType::UIText);
DEPENDENCY_PROPERTY_ATTACHED_WITH_CALLBACK(double, FontSize);
internal:
static LocalizationService ^ GetInstance();
static void OverrideWithLanguage(_In_ const wchar_t* const language);
Windows::UI::Xaml::FlowDirection GetFlowDirection();
bool IsRtlLayout();
bool GetOverrideFontApiValues();
@ -42,7 +39,17 @@ namespace CalculatorApp
Platform::String ^ GetFontFamilyOverride();
Windows::UI::Text::FontWeight GetFontWeightOverride();
double GetFontScaleFactorOverride(LanguageFontType fontType);
Windows::Globalization::NumberFormatting::DecimalFormatter ^ GetRegionalSettingsAwareDecimalFormatter();
Windows::Globalization::DateTimeFormatting::DateTimeFormatter ^ GetRegionalSettingsAwareDateTimeFormatter(_In_ Platform::String ^ format);
Windows::Globalization::DateTimeFormatting::DateTimeFormatter
^ GetRegionalSettingsAwareDateTimeFormatter(
_In_ Platform::String ^ format,
_In_ Platform::String ^ calendarIdentifier,
_In_ Platform::String ^ clockIdentifier);
Windows::Globalization::NumberFormatting::CurrencyFormatter ^ GetRegionalSettingsAwareCurrencyFormatter();
internal:
static void OverrideWithLanguage(_In_ const wchar_t* const language);
void Sort(std::vector<Platform::String ^>& source);
template <typename T>
@ -56,16 +63,6 @@ namespace CalculatorApp
});
}
Windows::Globalization::NumberFormatting::DecimalFormatter ^ GetRegionalSettingsAwareDecimalFormatter() const;
Windows::Globalization::DateTimeFormatting::DateTimeFormatter ^ GetRegionalSettingsAwareDateTimeFormatter(_In_ Platform::String ^ format) const;
Windows::Globalization::DateTimeFormatting::DateTimeFormatter
^ GetRegionalSettingsAwareDateTimeFormatter(
_In_ Platform::String ^ format,
_In_ Platform::String ^ calendarIdentifier,
_In_ Platform::String ^ clockIdentifier) const;
Windows::Globalization::NumberFormatting::CurrencyFormatter ^ GetRegionalSettingsAwareCurrencyFormatter() const;
static Platform::String ^ GetNarratorReadableToken(Platform::String ^ rawToken);
static Platform::String ^ GetNarratorReadableString(Platform::String ^ rawString);
@ -101,6 +98,5 @@ namespace CalculatorApp
double m_uiCaptionFontScaleFactorOverride;
std::locale m_locale;
};
}
}

View file

@ -6,22 +6,191 @@
#include <iterator>
namespace CalculatorApp
namespace CalculatorApp::ViewModel
{
namespace Common
{
class LocalizationSettings
public ref class LocalizationSettings sealed
{
private:
LocalizationSettings()
// Use DecimalFormatter as it respects the locale and the user setting
: LocalizationSettings(LocalizationService::GetInstance()->GetRegionalSettingsAwareDecimalFormatter())
{
Initialize(LocalizationService::GetInstance()->GetRegionalSettingsAwareDecimalFormatter());
}
public:
// This is only public for unit testing purposes.
LocalizationSettings(Windows::Globalization::NumberFormatting::DecimalFormatter ^ formatter)
{
Initialize(formatter);
}
// Provider of the singleton LocalizationSettings instance.
static LocalizationSettings^ GetInstance()
{
static LocalizationSettings^ localizationSettings = ref new LocalizationSettings();
return localizationSettings;
}
Platform::String ^ GetLocaleName()
{
return m_resolvedName;
}
bool IsDigitEnUsSetting()
{
return (this->GetDigitSymbolFromEnUsDigit('0') == L'0');
}
Platform::String ^ GetEnglishValueFromLocalizedDigits(Platform::String ^ localizedString)
{
if (m_resolvedName == L"en-US")
{
return localizedString;
}
std::wstring englishString;
englishString.reserve(localizedString->Length());
for (wchar_t ch : localizedString)
{
if (!IsEnUsDigit(ch))
{
auto it = std::find(m_digitSymbols.begin(), m_digitSymbols.end(), ch);
if (it != m_digitSymbols.end())
{
auto index = std::distance(m_digitSymbols.begin(), it);
ch = index.ToString()->Data()[0];
}
}
if (ch == m_decimalSeparator)
{
ch = L'.';
}
englishString += ch;
}
return ref new Platform::String(englishString.c_str());
}
Platform::String ^ RemoveGroupSeparators(Platform::String ^ source)
{
std::wstring destination;
std::copy_if(
begin(source), end(source), std::back_inserter(destination), [this](auto const c) { return c != L' ' && c != m_numberGroupSeparator; });
return ref new Platform::String(destination.c_str());
}
Platform::String ^ GetCalendarIdentifier()
{
return m_calendarIdentifier;
}
Windows::Globalization::DayOfWeek GetFirstDayOfWeek()
{
return m_firstDayOfWeek;
}
int GetCurrencyTrailingDigits()
{
return m_currencyTrailingDigits;
}
int GetCurrencySymbolPrecedence()
{
return m_currencySymbolPrecedence;
}
wchar_t GetDecimalSeparator()
{
return m_decimalSeparator;
}
wchar_t GetDigitSymbolFromEnUsDigit(wchar_t digitSymbol)
{
assert(digitSymbol >= L'0' && digitSymbol <= L'9');
int digit = digitSymbol - L'0';
return m_digitSymbols.at(digit); // throws on out of range
}
wchar_t GetNumberGroupSeparator()
{
return m_numberGroupSeparator;
}
bool IsEnUsDigit(wchar_t digit)
{
return (digit >= L'0' && digit <= L'9');
}
bool IsLocalizedDigit(wchar_t digit)
{
return std::find(m_digitSymbols.begin(), m_digitSymbols.end(), digit) != m_digitSymbols.end();
}
bool IsLocalizedHexDigit(wchar_t digit)
{
if (IsLocalizedDigit(digit))
{
return true;
}
return std::find(s_hexSymbols.begin(), s_hexSymbols.end(), digit) != s_hexSymbols.end();
}
Platform::String ^ GetListSeparatorWinRT()
{
return ref new Platform::String(GetListSeparator().c_str());
}
Platform::String ^ GetDecimalSeparatorStrWinRT()
{
return ref new Platform::String(GetDecimalSeparatorStr().c_str());
}
internal:
void LocalizeDisplayValue(_Inout_ std::wstring* stringToLocalize)
{
if (IsDigitEnUsSetting())
{
return;
}
for (wchar_t& ch : *stringToLocalize)
{
if (IsEnUsDigit(ch))
{
ch = GetDigitSymbolFromEnUsDigit(ch);
}
}
}
std::wstring GetDecimalSeparatorStr()
{
return std::wstring(1, m_decimalSeparator);
}
std::wstring GetNumberGroupingSeparatorStr()
{
return std::wstring(1, m_numberGroupSeparator);
}
std::wstring GetNumberGroupingStr()
{
return m_numberGrouping;
}
std::wstring GetListSeparator()
{
return m_listSeparator;
}
private:
void Initialize(Windows::Globalization::NumberFormatting::DecimalFormatter ^ formatter)
{
formatter->FractionDigits = 0;
formatter->IsDecimalPointAlwaysDisplayed = false;
@ -125,167 +294,6 @@ namespace CalculatorApp
m_firstDayOfWeek = static_cast<Windows::Globalization::DayOfWeek>((_wtoi(day) + 1) % 7); // static cast int to DayOfWeek enum
}
// A LocalizationSettings object is not copyable.
LocalizationSettings(const LocalizationSettings&) = delete;
LocalizationSettings& operator=(const LocalizationSettings&) = delete;
// A LocalizationSettings object is not moveable.
LocalizationSettings(LocalizationSettings&&) = delete;
LocalizationSettings& operator=(LocalizationSettings&&) = delete;
// Provider of the singleton LocalizationSettings instance.
static const LocalizationSettings& GetInstance()
{
static const LocalizationSettings localizationSettings;
return localizationSettings;
}
Platform::String ^ GetLocaleName() const
{
return m_resolvedName;
}
bool IsDigitEnUsSetting() const
{
return (this->GetDigitSymbolFromEnUsDigit('0') == L'0');
}
void LocalizeDisplayValue(_Inout_ std::wstring* stringToLocalize) const
{
if (IsDigitEnUsSetting())
{
return;
}
for (wchar_t& ch : *stringToLocalize)
{
if (IsEnUsDigit(ch))
{
ch = GetDigitSymbolFromEnUsDigit(ch);
}
}
}
Platform::String ^ GetEnglishValueFromLocalizedDigits(Platform::String ^ localizedString) const
{
if (m_resolvedName == L"en-US")
{
return localizedString;
}
std::wstring englishString;
englishString.reserve(localizedString->Length());
for (wchar_t ch : localizedString)
{
if (!IsEnUsDigit(ch))
{
auto it = std::find(m_digitSymbols.begin(), m_digitSymbols.end(), ch);
if (it != m_digitSymbols.end())
{
auto index = std::distance(m_digitSymbols.begin(), it);
ch = index.ToString()->Data()[0];
}
}
if (ch == m_decimalSeparator)
{
ch = L'.';
}
englishString += ch;
}
return ref new Platform::String(englishString.c_str());
}
bool IsEnUsDigit(const wchar_t digit) const
{
return (digit >= L'0' && digit <= L'9');
}
bool IsLocalizedDigit(const wchar_t digit) const
{
return std::find(m_digitSymbols.begin(), m_digitSymbols.end(), digit) != m_digitSymbols.end();
}
bool IsLocalizedHexDigit(const wchar_t digit) const
{
if (IsLocalizedDigit(digit))
{
return true;
}
return std::find(s_hexSymbols.begin(), s_hexSymbols.end(), digit) != s_hexSymbols.end();
}
wchar_t GetDigitSymbolFromEnUsDigit(wchar_t digitSymbol) const
{
assert(digitSymbol >= L'0' && digitSymbol <= L'9');
int digit = digitSymbol - L'0';
return m_digitSymbols.at(digit); // throws on out of range
}
wchar_t GetDecimalSeparator() const
{
return m_decimalSeparator;
}
wchar_t GetNumberGroupSeparator() const
{
return m_numberGroupSeparator;
}
std::wstring GetDecimalSeparatorStr() const
{
return std::wstring(1, m_decimalSeparator);
}
std::wstring GetNumberGroupingSeparatorStr() const
{
return std::wstring(1, m_numberGroupSeparator);
}
std::wstring GetNumberGroupingStr() const
{
return m_numberGrouping;
}
Platform::String ^ RemoveGroupSeparators(Platform::String ^ source) const
{
std::wstring destination;
std::copy_if(
begin(source), end(source), std::back_inserter(destination), [this](auto const c) { return c != L' ' && c != m_numberGroupSeparator; });
return ref new Platform::String(destination.c_str());
}
Platform::String ^ GetCalendarIdentifier() const
{
return m_calendarIdentifier;
}
std::wstring GetListSeparator() const
{
return m_listSeparator;
}
Windows::Globalization::DayOfWeek GetFirstDayOfWeek() const
{
return m_firstDayOfWeek;
}
int GetCurrencyTrailingDigits() const
{
return m_currencyTrailingDigits;
}
int GetCurrencySymbolPrecedence() const
{
return m_currencySymbolPrecedence;
}
private:
static Platform::String^ GetCalendarIdentifierFromCalid(CALID calId)
{
switch (calId)

View file

@ -5,7 +5,7 @@
#include "AppResourceProvider.h"
namespace CalculatorApp
namespace CalculatorApp::ViewModel
{
namespace Common
{
@ -16,7 +16,7 @@ namespace CalculatorApp
{
std::wstring returnString = L"";
const UINT32 length = 1024;
std::unique_ptr<wchar_t[]> spBuffer = std::unique_ptr<wchar_t[]>(new wchar_t[length]);
std::unique_ptr<wchar_t[]> spBuffer = std::make_unique<wchar_t[]>(length);
va_list args = NULL;
va_start(args, pMessage);
DWORD fmtReturnVal = FormatMessage(FORMAT_MESSAGE_FROM_STRING, pMessage->Data(), 0, 0, spBuffer.get(), length, &args);

View file

@ -3,7 +3,7 @@
#pragma once
namespace CalculatorApp
namespace CalculatorApp::ViewModel
{
namespace Common
{

View file

@ -8,11 +8,11 @@
#include <initializer_list>
using namespace CalculatorApp;
using namespace CalculatorApp::Common;
using namespace CalculatorApp::ViewModel::Common;
using namespace CalculatorApp::ViewModel;
using namespace Concurrency;
using namespace Platform;
using namespace Platform::Collections;
using namespace std;
using namespace Windows::Foundation::Collections;
using namespace Windows::Management::Policies;
using namespace Windows::System;
@ -47,451 +47,236 @@ static constexpr int CURRENCY_ID = 16;
static constexpr int GRAPHING_ID = 17;
// ^^^ THESE CONSTANTS SHOULD NEVER CHANGE ^^^
wchar_t* towchar_t(int number)
namespace // put the utils within this TU
{
auto wstr = to_wstring(number);
return _wcsdup(wstr.c_str());
}
Platform::String^ CurrentUserId;
std::mutex GraphingModeCheckMutex;
bool IsGraphingModeAvailable()
{
static bool supportGraph = Windows::Foundation::Metadata::ApiInformation::IsMethodPresent("Windows.UI.Text.RichEditTextDocument", "GetMath");
return supportGraph;
}
Box<bool> ^ _isGraphingModeEnabledCached = nullptr;
bool IsGraphingModeEnabled(User ^ currentUser = nullptr)
{
if (!IsGraphingModeAvailable())
bool IsGraphingModeEnabled()
{
return false;
}
static bool isChecked = false;
static bool isEnabled = false;
if (_isGraphingModeEnabledCached != nullptr)
{
return _isGraphingModeEnabledCached->Value;
}
if (!currentUser)
{
return true;
}
auto namedPolicyData = NamedPolicy::GetPolicyFromPathForUser(currentUser, L"Education", L"AllowGraphingCalculator");
_isGraphingModeEnabledCached = namedPolicyData->GetBoolean() == true;
return _isGraphingModeEnabledCached->Value;
}
// The order of items in this list determines the order of items in the menu.
static list<NavCategoryInitializer> s_categoryManifest = [] {
auto res = list<NavCategoryInitializer>{ NavCategoryInitializer{ ViewMode::Standard,
STANDARD_ID,
L"Standard",
L"StandardMode",
L"\uE8EF",
CategoryGroupType::Calculator,
MyVirtualKey::Number1,
L"1",
SUPPORTS_ALL,
true },
NavCategoryInitializer{ ViewMode::Scientific,
SCIENTIFIC_ID,
L"Scientific",
L"ScientificMode",
L"\uF196",
CategoryGroupType::Calculator,
MyVirtualKey::Number2,
L"2",
SUPPORTS_ALL,
true } };
int currentIndex = 3;
bool supportGraphingCalculator = IsGraphingModeAvailable();
if (supportGraphingCalculator)
{
bool isEnabled = IsGraphingModeEnabled();
res.push_back(NavCategoryInitializer{ ViewMode::Graphing,
GRAPHING_ID,
L"Graphing",
L"GraphingCalculatorMode",
L"\uF770",
CategoryGroupType::Calculator,
MyVirtualKey::Number3,
L"3",
SUPPORTS_ALL,
isEnabled });
++currentIndex;
}
res.insert(
res.end(),
{ NavCategoryInitializer{ ViewMode::Programmer,
PROGRAMMER_ID,
L"Programmer",
L"ProgrammerMode",
L"\uECCE",
CategoryGroupType::Calculator,
supportGraphingCalculator ? MyVirtualKey::Number4 : MyVirtualKey::Number3,
towchar_t(currentIndex++),
SUPPORTS_ALL,
true },
NavCategoryInitializer{ ViewMode::Date,
DATE_ID,
L"Date",
L"DateCalculationMode",
L"\uE787",
CategoryGroupType::Calculator,
supportGraphingCalculator ? MyVirtualKey::Number5 : MyVirtualKey::Number4,
towchar_t(currentIndex++),
SUPPORTS_ALL,
true },
NavCategoryInitializer{ ViewMode::Currency,
CURRENCY_ID,
L"Currency",
L"CategoryName_Currency",
L"\uEB0D",
CategoryGroupType::Converter,
MyVirtualKey::None,
nullptr,
POSITIVE_ONLY,
true },
NavCategoryInitializer{ ViewMode::Volume,
VOLUME_ID,
L"Volume",
L"CategoryName_Volume",
L"\uF1AA",
CategoryGroupType::Converter,
MyVirtualKey::None,
nullptr,
POSITIVE_ONLY,
true },
NavCategoryInitializer{ ViewMode::Length,
LENGTH_ID,
L"Length",
L"CategoryName_Length",
L"\uECC6",
CategoryGroupType::Converter,
MyVirtualKey::None,
nullptr,
POSITIVE_ONLY,
true },
NavCategoryInitializer{ ViewMode::Weight,
WEIGHT_ID,
L"Weight and Mass",
L"CategoryName_Weight",
L"\uF4C1",
CategoryGroupType::Converter,
MyVirtualKey::None,
nullptr,
POSITIVE_ONLY,
true },
NavCategoryInitializer{ ViewMode::Temperature,
TEMPERATURE_ID,
L"Temperature",
L"CategoryName_Temperature",
L"\uE7A3",
CategoryGroupType::Converter,
MyVirtualKey::None,
nullptr,
SUPPORTS_NEGATIVE,
true },
NavCategoryInitializer{ ViewMode::Energy,
ENERGY_ID,
L"Energy",
L"CategoryName_Energy",
L"\uECAD",
CategoryGroupType::Converter,
MyVirtualKey::None,
nullptr,
POSITIVE_ONLY,
true },
NavCategoryInitializer{ ViewMode::Area,
AREA_ID,
L"Area",
L"CategoryName_Area",
L"\uE809",
CategoryGroupType::Converter,
MyVirtualKey::None,
nullptr,
POSITIVE_ONLY,
true },
NavCategoryInitializer{ ViewMode::Speed,
SPEED_ID,
L"Speed",
L"CategoryName_Speed",
L"\uEADA",
CategoryGroupType::Converter,
MyVirtualKey::None,
nullptr,
POSITIVE_ONLY,
true },
NavCategoryInitializer{ ViewMode::Time,
TIME_ID,
L"Time",
L"CategoryName_Time",
L"\uE917",
CategoryGroupType::Converter,
MyVirtualKey::None,
nullptr,
POSITIVE_ONLY,
true },
NavCategoryInitializer{ ViewMode::Power,
POWER_ID,
L"Power",
L"CategoryName_Power",
L"\uE945",
CategoryGroupType::Converter,
MyVirtualKey::None,
nullptr,
SUPPORTS_NEGATIVE,
true },
NavCategoryInitializer{ ViewMode::Data,
DATA_ID,
L"Data",
L"CategoryName_Data",
L"\uF20F",
CategoryGroupType::Converter,
MyVirtualKey::None,
nullptr,
POSITIVE_ONLY,
true },
NavCategoryInitializer{ ViewMode::Pressure,
PRESSURE_ID,
L"Pressure",
L"CategoryName_Pressure",
L"\uEC4A",
CategoryGroupType::Converter,
MyVirtualKey::None,
nullptr,
POSITIVE_ONLY,
true },
NavCategoryInitializer{ ViewMode::Angle,
ANGLE_ID,
L"Angle",
L"CategoryName_Angle",
L"\uF515",
CategoryGroupType::Converter,
MyVirtualKey::None,
nullptr,
SUPPORTS_NEGATIVE,
true } });
return res;
}();
void NavCategory::InitializeCategoryManifest(User ^ user)
{
int i = 0;
for (NavCategoryInitializer category : s_categoryManifest)
{
if (category.viewMode == ViewMode::Graphing)
std::scoped_lock<std::mutex> lock(GraphingModeCheckMutex);
if (isChecked)
{
auto navCatInit = s_categoryManifest.begin();
std::advance(navCatInit, i);
(*navCatInit).isEnabled = IsGraphingModeEnabled(user);
break;
return isEnabled;
}
else
{
i++;
}
}
}
// This function should only be used when storing the mode to app data.
int NavCategory::Serialize(ViewMode mode)
{
auto iter =
find_if(begin(s_categoryManifest), end(s_categoryManifest), [mode](const NavCategoryInitializer& initializer) { return initializer.viewMode == mode; });
return (iter != s_categoryManifest.end()) ? iter->serializationId : -1;
}
// This function should only be used when restoring the mode from app data.
ViewMode NavCategory::Deserialize(Platform::Object ^ obj)
{
// If we cast directly to ViewMode we will fail
// because we technically store an int.
// Need to cast to int, then ViewMode.
auto boxed = dynamic_cast<Box<int> ^>(obj);
if (boxed != nullptr)
{
int serializationId = boxed->Value;
auto iter = find_if(begin(s_categoryManifest), end(s_categoryManifest), [serializationId](const NavCategoryInitializer& initializer) {
return initializer.serializationId == serializationId;
});
if (iter != s_categoryManifest.end())
{
if (iter->viewMode == ViewMode::Graphing)
auto user = User::GetFromId(CurrentUserId);
if (user == nullptr)
{
// check if the user is allowed to use this feature
if (!IsGraphingModeEnabled())
{
return ViewMode::None;
}
return true;
}
return iter->viewMode;
auto namedPolicyData = NamedPolicy::GetPolicyFromPathForUser(
user,
L"Education",
L"AllowGraphingCalculator");
isEnabled = namedPolicyData->GetBoolean();
isChecked = true;
return isEnabled;
}
}
return ViewMode::None;
}
// The order of items in this list determines the order of items in the menu.
const std::vector<NavCategoryInitializer> s_categoryManifest {
NavCategoryInitializer{ ViewMode::Standard,
STANDARD_ID,
L"Standard",
L"StandardMode",
L"\uE8EF",
CategoryGroupType::Calculator,
MyVirtualKey::Number1,
L"1",
SUPPORTS_ALL },
NavCategoryInitializer{ ViewMode::Scientific,
SCIENTIFIC_ID,
L"Scientific",
L"ScientificMode",
L"\uF196",
CategoryGroupType::Calculator,
MyVirtualKey::Number2,
L"2",
SUPPORTS_ALL },
NavCategoryInitializer{ ViewMode::Graphing,
GRAPHING_ID,
L"Graphing",
L"GraphingCalculatorMode",
L"\uF770",
CategoryGroupType::Calculator,
MyVirtualKey::Number3,
L"3",
SUPPORTS_ALL },
NavCategoryInitializer{ ViewMode::Programmer,
PROGRAMMER_ID,
L"Programmer",
L"ProgrammerMode",
L"\uECCE",
CategoryGroupType::Calculator,
MyVirtualKey::Number4,
L"4",
SUPPORTS_ALL },
NavCategoryInitializer{ ViewMode::Date,
DATE_ID,
L"Date",
L"DateCalculationMode",
L"\uE787",
CategoryGroupType::Calculator,
MyVirtualKey::Number5,
L"5",
SUPPORTS_ALL },
NavCategoryInitializer{ ViewMode::Currency,
CURRENCY_ID,
L"Currency",
L"CategoryName_Currency",
L"\uEB0D",
CategoryGroupType::Converter,
MyVirtualKey::None,
std::nullopt,
POSITIVE_ONLY },
NavCategoryInitializer{ ViewMode::Volume,
VOLUME_ID,
L"Volume",
L"CategoryName_Volume",
L"\uF1AA",
CategoryGroupType::Converter,
MyVirtualKey::None,
std::nullopt,
POSITIVE_ONLY },
NavCategoryInitializer{ ViewMode::Length,
LENGTH_ID,
L"Length",
L"CategoryName_Length",
L"\uECC6",
CategoryGroupType::Converter,
MyVirtualKey::None,
std::nullopt,
POSITIVE_ONLY },
NavCategoryInitializer{ ViewMode::Weight,
WEIGHT_ID,
L"Weight and Mass",
L"CategoryName_Weight",
L"\uF4C1",
CategoryGroupType::Converter,
MyVirtualKey::None,
std::nullopt,
POSITIVE_ONLY },
NavCategoryInitializer{ ViewMode::Temperature,
TEMPERATURE_ID,
L"Temperature",
L"CategoryName_Temperature",
L"\uE7A3",
CategoryGroupType::Converter,
MyVirtualKey::None,
std::nullopt,
SUPPORTS_NEGATIVE },
NavCategoryInitializer{ ViewMode::Energy,
ENERGY_ID,
L"Energy",
L"CategoryName_Energy",
L"\uECAD",
CategoryGroupType::Converter,
MyVirtualKey::None,
std::nullopt,
POSITIVE_ONLY },
NavCategoryInitializer{ ViewMode::Area,
AREA_ID,
L"Area",
L"CategoryName_Area",
L"\uE809",
CategoryGroupType::Converter,
MyVirtualKey::None,
std::nullopt,
POSITIVE_ONLY },
NavCategoryInitializer{ ViewMode::Speed,
SPEED_ID,
L"Speed",
L"CategoryName_Speed",
L"\uEADA",
CategoryGroupType::Converter,
MyVirtualKey::None,
std::nullopt,
POSITIVE_ONLY },
NavCategoryInitializer{ ViewMode::Time,
TIME_ID,
L"Time",
L"CategoryName_Time",
L"\uE917",
CategoryGroupType::Converter,
MyVirtualKey::None,
std::nullopt,
POSITIVE_ONLY },
NavCategoryInitializer{ ViewMode::Power,
POWER_ID,
L"Power",
L"CategoryName_Power",
L"\uE945",
CategoryGroupType::Converter,
MyVirtualKey::None,
std::nullopt,
SUPPORTS_NEGATIVE },
NavCategoryInitializer{ ViewMode::Data,
DATA_ID,
L"Data",
L"CategoryName_Data",
L"\uF20F",
CategoryGroupType::Converter,
MyVirtualKey::None,
std::nullopt,
POSITIVE_ONLY },
NavCategoryInitializer{ ViewMode::Pressure,
PRESSURE_ID,
L"Pressure",
L"CategoryName_Pressure",
L"\uEC4A",
CategoryGroupType::Converter,
MyVirtualKey::None,
std::nullopt,
POSITIVE_ONLY },
NavCategoryInitializer{ ViewMode::Angle,
ANGLE_ID,
L"Angle",
L"CategoryName_Angle",
L"\uF515",
CategoryGroupType::Converter,
MyVirtualKey::None,
std::nullopt,
SUPPORTS_NEGATIVE },
};
} // namespace unnamed
bool NavCategory::IsValidViewMode(ViewMode mode)
{
auto iter =
find_if(begin(s_categoryManifest), end(s_categoryManifest), [mode](const NavCategoryInitializer& initializer) { return initializer.viewMode == mode; });
return iter != s_categoryManifest.end();
}
bool NavCategory::IsViewModeEnabled(ViewMode mode)
{
auto iter = find_if(begin(s_categoryManifest), end(s_categoryManifest), [mode](const NavCategoryInitializer& initializer) {
return initializer.viewMode == mode && initializer.isEnabled;
});
return iter != s_categoryManifest.end();
}
bool NavCategory::IsCalculatorViewMode(ViewMode mode)
bool NavCategory::IsCalculatorViewMode(ViewModeType mode)
{
// Historically, Calculator modes are Standard, Scientific, and Programmer.
return !IsDateCalculatorViewMode(mode) && !IsGraphingCalculatorViewMode(mode) && IsModeInCategoryGroup(mode, CategoryGroupType::Calculator);
}
bool NavCategory::IsGraphingCalculatorViewMode(ViewMode mode)
bool NavCategory::IsGraphingCalculatorViewMode(ViewModeType mode)
{
return mode == ViewMode::Graphing;
return mode == ViewModeType::Graphing;
}
bool NavCategory::IsDateCalculatorViewMode(ViewMode mode)
bool NavCategory::IsDateCalculatorViewMode(ViewModeType mode)
{
return mode == ViewMode::Date;
return mode == ViewModeType::Date;
}
bool NavCategory::IsConverterViewMode(ViewMode mode)
bool NavCategory::IsConverterViewMode(ViewModeType mode)
{
return IsModeInCategoryGroup(mode, CategoryGroupType::Converter);
}
bool NavCategory::IsModeInCategoryGroup(ViewMode mode, CategoryGroupType type)
bool NavCategory::IsModeInCategoryGroup(ViewModeType mode, CategoryGroupType type)
{
auto iter = find_if(begin(s_categoryManifest), end(s_categoryManifest), [mode, type](const NavCategoryInitializer& initializer) {
return initializer.viewMode == mode && initializer.groupType == type;
});
return iter != s_categoryManifest.end();
}
String ^ NavCategory::GetFriendlyName(ViewMode mode)
{
auto iter =
find_if(begin(s_categoryManifest), end(s_categoryManifest), [mode](const NavCategoryInitializer& initializer) { return initializer.viewMode == mode; });
return (iter != s_categoryManifest.end()) ? StringReference(iter->friendlyName) : L"None";
}
ViewMode NavCategory::GetViewModeForFriendlyName(String ^ name)
{
auto iter = find_if(begin(s_categoryManifest), end(s_categoryManifest), [name](const NavCategoryInitializer& initializer) {
return wcscmp(initializer.friendlyName, name->Data()) == 0;
});
return (iter != s_categoryManifest.end()) ? iter->viewMode : ViewMode::None;
}
String ^ NavCategory::GetNameResourceKey(ViewMode mode)
{
auto iter =
find_if(begin(s_categoryManifest), end(s_categoryManifest), [mode](const NavCategoryInitializer& initializer) { return initializer.viewMode == mode; });
return (iter != s_categoryManifest.end()) ? StringReference(iter->nameResourceKey) + "Text" : nullptr;
}
CategoryGroupType NavCategory::GetGroupType(ViewMode mode)
{
auto iter =
find_if(begin(s_categoryManifest), end(s_categoryManifest), [mode](const NavCategoryInitializer& initializer) { return initializer.viewMode == mode; });
return (iter != s_categoryManifest.end()) ? iter->groupType : CategoryGroupType::None;
}
// GetIndex is 0-based, GetPosition is 1-based
int NavCategory::GetIndex(ViewMode mode)
{
int position = NavCategory::GetPosition(mode);
return max(-1, position - 1);
}
int NavCategory::GetFlatIndex(ViewMode mode)
{
int index = -1;
CategoryGroupType type = CategoryGroupType::None;
auto iter = find_if(begin(s_categoryManifest), end(s_categoryManifest), [mode, &type, &index](const NavCategoryInitializer& initializer) {
index++;
if (initializer.groupType != type)
{
type = initializer.groupType;
index++;
}
return initializer.viewMode == mode;
});
return (iter != s_categoryManifest.end()) ? index : -1;
}
// GetIndex is 0-based, GetPosition is 1-based
int NavCategory::GetIndexInGroup(ViewMode mode, CategoryGroupType type)
{
int index = -1;
auto iter = find_if(begin(s_categoryManifest), end(s_categoryManifest), [mode, type, &index](const NavCategoryInitializer& initializer) {
if (initializer.groupType == type)
{
index++;
return initializer.viewMode == mode;
}
return false;
});
return (iter != s_categoryManifest.end()) ? index : -1;
}
// GetIndex is 0-based, GetPosition is 1-based
int NavCategory::GetPosition(ViewMode mode)
{
int position = 0;
auto iter = find_if(begin(s_categoryManifest), end(s_categoryManifest), [mode, &position](const NavCategoryInitializer& initializer) {
position++;
return initializer.viewMode == mode;
});
return (iter != s_categoryManifest.end()) ? position : -1;
}
ViewMode NavCategory::GetViewModeForVirtualKey(MyVirtualKey virtualKey)
{
auto iter = find_if(begin(s_categoryManifest), end(s_categoryManifest), [virtualKey](const NavCategoryInitializer& initializer) {
return initializer.virtualKey == virtualKey;
});
return (iter != s_categoryManifest.end()) ? iter->viewMode : ViewMode::None;
}
vector<MyVirtualKey> NavCategory::GetCategoryAcceleratorKeys()
{
vector<MyVirtualKey> accelerators{};
for (auto category : s_categoryManifest)
{
if (category.virtualKey != MyVirtualKey::None)
{
accelerators.push_back(category.virtualKey);
}
}
return accelerators;
return std::any_of(
s_categoryManifest.cbegin(),
s_categoryManifest.cend(),
[mode, type](const auto& initializer) {
return initializer.viewMode == mode && initializer.groupType == type;
});
}
NavCategoryGroup::NavCategoryGroup(const NavCategoryGroupInitializer& groupInitializer)
@ -521,32 +306,225 @@ NavCategoryGroup::NavCategoryGroup(const NavCategoryGroupInitializer& groupIniti
categoryName,
categoryAutomationName,
StringReference(categoryInitializer.glyph),
categoryInitializer.accessKey != nullptr ? ref new String(categoryInitializer.accessKey)
categoryInitializer.accessKey.has_value() ? ref new String(categoryInitializer.accessKey->c_str())
: resProvider->GetResourceString(nameResourceKey + "AccessKey"),
groupMode,
categoryInitializer.viewMode,
categoryInitializer.supportsNegative,
categoryInitializer.isEnabled));
categoryInitializer.viewMode != ViewMode::Graphing));
}
}
}
IObservableVector<NavCategoryGroup ^> ^ NavCategoryGroup::CreateMenuOptions()
void NavCategoryStates::SetCurrentUser(Platform::String^ userId)
{
std::scoped_lock<std::mutex> lock(GraphingModeCheckMutex);
CurrentUserId = userId;
}
IObservableVector<NavCategoryGroup ^> ^ NavCategoryStates::CreateMenuOptions()
{
auto menuOptions = ref new Vector<NavCategoryGroup ^>();
menuOptions->Append(CreateCalculatorCategory());
menuOptions->Append(CreateConverterCategory());
menuOptions->Append(CreateCalculatorCategoryGroup());
menuOptions->Append(CreateConverterCategoryGroup());
return menuOptions;
}
NavCategoryGroup ^ NavCategoryGroup::CreateCalculatorCategory()
NavCategoryGroup ^ NavCategoryStates::CreateCalculatorCategoryGroup()
{
return ref new NavCategoryGroup(
NavCategoryGroupInitializer{ CategoryGroupType::Calculator, L"CalculatorModeTextCaps", L"CalculatorModeText", L"CalculatorModePluralText" });
}
NavCategoryGroup ^ NavCategoryGroup::CreateConverterCategory()
NavCategoryGroup ^ NavCategoryStates::CreateConverterCategoryGroup()
{
return ref new NavCategoryGroup(
NavCategoryGroupInitializer{ CategoryGroupType::Converter, L"ConverterModeTextCaps", L"ConverterModeText", L"ConverterModePluralText" });
}
// This function should only be used when storing the mode to app data.
int NavCategoryStates::Serialize(ViewMode mode)
{
const auto& citer = find_if(
cbegin(s_categoryManifest),
cend(s_categoryManifest),
[mode](const auto& initializer) { return initializer.viewMode == mode; });
return (citer != s_categoryManifest.cend()) ? citer->serializationId : -1;
}
// This function should only be used when restoring the mode from app data.
ViewMode NavCategoryStates::Deserialize(Platform::Object ^ obj)
{
// If we cast directly to ViewMode we will fail
// because we technically store an int.
// Need to cast to int, then ViewMode.
auto boxed = dynamic_cast<Box<int> ^>(obj);
if (boxed != nullptr)
{
int serializationId = boxed->Value;
const auto& citer = find_if(
cbegin(s_categoryManifest),
cend(s_categoryManifest),
[serializationId](const auto& initializer) { return initializer.serializationId == serializationId; });
return citer != s_categoryManifest.cend() ?
(citer->viewMode == ViewMode::Graphing ?
(IsGraphingModeEnabled() ? citer->viewMode : ViewMode::None)
: citer->viewMode)
: ViewMode::None;
}
else
{
return ViewMode::None;
}
}
ViewMode NavCategoryStates::GetViewModeForFriendlyName(String ^ name)
{
const auto& citer = find_if(
cbegin(s_categoryManifest),
cend(s_categoryManifest),
[name](const auto& initializer) { return wcscmp(initializer.friendlyName, name->Data()) == 0; });
return (citer != s_categoryManifest.cend()) ? citer->viewMode : ViewMode::None;
}
String ^ NavCategoryStates::GetFriendlyName(ViewMode mode)
{
const auto& citer = find_if(
cbegin(s_categoryManifest),
cend(s_categoryManifest),
[mode](const auto& initializer) { return initializer.viewMode == mode; });
return (citer != s_categoryManifest.cend()) ? StringReference(citer->friendlyName) : L"None";
}
String ^ NavCategoryStates::GetNameResourceKey(ViewMode mode)
{
const auto& citer = find_if(
cbegin(s_categoryManifest),
cend(s_categoryManifest),
[mode](const auto& initializer) { return initializer.viewMode == mode; });
return (citer != s_categoryManifest.cend()) ? StringReference(citer->nameResourceKey) + "Text" : nullptr;
}
CategoryGroupType NavCategoryStates::GetGroupType(ViewMode mode)
{
const auto& citer = find_if(
cbegin(s_categoryManifest),
cend(s_categoryManifest),
[mode](const auto& initializer) { return initializer.viewMode == mode; });
return (citer != s_categoryManifest.cend()) ? citer->groupType : CategoryGroupType::None;
}
// GetIndex is 0-based, GetPosition is 1-based
int NavCategoryStates::GetIndex(ViewMode mode)
{
int position = GetPosition(mode);
return std::max(-1, position - 1);
}
int NavCategoryStates::GetFlatIndex(ViewMode mode)
{
int index = -1;
CategoryGroupType type = CategoryGroupType::None;
const auto& citer = find_if(
cbegin(s_categoryManifest),
cend(s_categoryManifest),
[mode, &type, &index](const auto& initializer) {
++index;
if (initializer.groupType != type)
{
type = initializer.groupType;
++index;
}
return initializer.viewMode == mode;
});
return (citer != s_categoryManifest.cend()) ? index : -1;
}
// GetIndex is 0-based, GetPosition is 1-based
int NavCategoryStates::GetIndexInGroup(ViewMode mode, CategoryGroupType type)
{
int index = -1;
const auto& citer = find_if(
cbegin(s_categoryManifest),
cend(s_categoryManifest),
[mode, type, &index](const auto& initializer) {
if (initializer.groupType == type)
{
++index;
return initializer.viewMode == mode;
}
return false;
});
return (citer != s_categoryManifest.cend()) ? index : -1;
}
// GetIndex is 0-based, GetPosition is 1-based
int NavCategoryStates::GetPosition(ViewMode mode)
{
int position = 0;
const auto& citer = find_if(
cbegin(s_categoryManifest),
cend(s_categoryManifest),
[mode, &position](const auto& initializer) {
++position;
return initializer.viewMode == mode;
});
return (citer != s_categoryManifest.cend()) ? position : -1;
}
ViewMode NavCategoryStates::GetViewModeForVirtualKey(MyVirtualKey virtualKey)
{
const auto& citer = find_if(
cbegin(s_categoryManifest),
cend(s_categoryManifest),
[virtualKey](const auto& initializer) { return initializer.virtualKey == virtualKey; });
return (citer != s_categoryManifest.end()) ? citer->viewMode : ViewMode::None;
}
void NavCategoryStates::GetCategoryAcceleratorKeys(IVector<MyVirtualKey> ^ accelerators)
{
if (accelerators != nullptr)
{
accelerators->Clear();
for (const auto& category : s_categoryManifest)
{
if (category.virtualKey != MyVirtualKey::None)
{
accelerators->Append(category.virtualKey);
}
}
}
}
bool NavCategoryStates::IsValidViewMode(ViewMode mode)
{
const auto& citer = find_if(
cbegin(s_categoryManifest),
cend(s_categoryManifest),
[mode](const auto& initializer) { return initializer.viewMode == mode; });
return citer != s_categoryManifest.cend();
}
bool NavCategoryStates::IsViewModeEnabled(ViewMode mode)
{
if (mode != ViewMode::Graphing)
{
return true;
}
else
{
return IsGraphingModeEnabled();
}
}

View file

@ -17,7 +17,7 @@
#include "Utils.h"
#include "MyVirtualKey.h"
namespace CalculatorApp
namespace CalculatorApp::ViewModel
{
namespace Common
{
@ -59,46 +59,21 @@ namespace CalculatorApp
private
struct NavCategoryInitializer
{
constexpr NavCategoryInitializer(
ViewMode mode,
int id,
wchar_t const* name,
wchar_t const* nameKey,
wchar_t const* glyph,
CategoryGroupType group,
MyVirtualKey vKey,
wchar_t const* aKey,
bool categorySupportsNegative,
bool enabled)
: viewMode(mode)
, serializationId(id)
, friendlyName(name)
, nameResourceKey(nameKey)
, glyph(glyph)
, groupType(group)
, virtualKey(vKey)
, accessKey(aKey)
, supportsNegative(categorySupportsNegative)
, isEnabled(enabled)
{
}
const ViewMode viewMode;
const int serializationId;
const wchar_t* const friendlyName;
const wchar_t* const nameResourceKey;
const wchar_t* const glyph;
const CategoryGroupType groupType;
const MyVirtualKey virtualKey;
const wchar_t* const accessKey;
const bool supportsNegative;
bool isEnabled;
ViewMode viewMode;
int serializationId;
const wchar_t* friendlyName;
const wchar_t* nameResourceKey;
const wchar_t* glyph;
CategoryGroupType groupType;
MyVirtualKey virtualKey;
std::optional<std::wstring> accessKey;
bool supportsNegative;
};
private
struct NavCategoryGroupInitializer
{
constexpr NavCategoryGroupInitializer(CategoryGroupType t, wchar_t const* h, wchar_t const* n, wchar_t const* a)
NavCategoryGroupInitializer(CategoryGroupType t, wchar_t const* h, wchar_t const* n, wchar_t const* a)
: type(t)
, headerResourceKey(h)
, modeResourceKey(n)
@ -112,36 +87,85 @@ namespace CalculatorApp
const wchar_t* automationResourceKey;
};
[Windows::UI::Xaml::Data::Bindable] public ref class NavCategory sealed : public Windows::UI::Xaml::Data::INotifyPropertyChanged
[Windows::UI::Xaml::Data::Bindable]
public ref class NavCategory sealed : public Windows::UI::Xaml::Data::INotifyPropertyChanged
{
private:
using ViewModeType = ::CalculatorApp::ViewModel::Common::ViewMode;
public:
OBSERVABLE_OBJECT();
PROPERTY_R(Platform::String ^, Name);
PROPERTY_R(Platform::String ^, AutomationName);
PROPERTY_R(Platform::String ^, Glyph);
PROPERTY_R(ViewMode, Mode);
PROPERTY_R(ViewModeType, ViewMode);
PROPERTY_R(Platform::String ^, AccessKey);
PROPERTY_R(bool, SupportsNegative);
PROPERTY_R(bool, IsEnabled);
PROPERTY_RW(bool, IsEnabled);
property Platform::String
^ AutomationId { Platform::String ^ get() { return m_Mode.ToString(); } }
^ AutomationId { Platform::String ^ get() { return m_ViewMode.ToString(); } }
static bool IsCalculatorViewMode(ViewModeType mode);
static bool IsGraphingCalculatorViewMode(ViewModeType mode);
static bool IsDateCalculatorViewMode(ViewModeType mode);
static bool IsConverterViewMode(ViewModeType mode);
internal : NavCategory(
Platform::String ^ name,
Platform::String ^ automationName,
Platform::String ^ glyph,
Platform::String ^ accessKey,
Platform::String ^ mode,
ViewModeType viewMode,
bool supportsNegative,
bool isEnabled)
: m_Name(name)
, m_AutomationName(automationName)
, m_Glyph(glyph)
, m_AccessKey(accessKey)
, m_modeString(mode)
, m_ViewMode(viewMode)
, m_SupportsNegative(supportsNegative)
, m_IsEnabled(isEnabled)
{
}
private:
static bool IsModeInCategoryGroup(ViewModeType mode, CategoryGroupType groupType);
Platform::String ^ m_modeString;
};
[Windows::UI::Xaml::Data::Bindable]
public ref class NavCategoryGroup sealed : public Windows::UI::Xaml::Data::INotifyPropertyChanged
{
internal:
NavCategoryGroup(const NavCategoryGroupInitializer& groupInitializer);
public:
OBSERVABLE_OBJECT();
OBSERVABLE_PROPERTY_R(Platform::String ^, Name);
OBSERVABLE_PROPERTY_R(Platform::String ^, AutomationName);
OBSERVABLE_PROPERTY_R(CategoryGroupType, GroupType);
OBSERVABLE_PROPERTY_R(Windows::Foundation::Collections::IObservableVector<NavCategory ^> ^, Categories);
};
public ref class NavCategoryStates sealed
{
public:
static void SetCurrentUser(Platform::String^ user);
static Windows::Foundation::Collections::IObservableVector<NavCategoryGroup ^> ^ CreateMenuOptions();
static NavCategoryGroup ^ CreateCalculatorCategoryGroup();
static NavCategoryGroup ^ CreateConverterCategoryGroup();
static bool IsValidViewMode(ViewMode mode);
static bool IsViewModeEnabled(ViewMode mode);
// For saving/restoring last mode used.
static int Serialize(ViewMode mode);
static ViewMode Deserialize(Platform::Object ^ obj);
// Query properties from states
static ViewMode GetViewModeForFriendlyName(Platform::String ^ name);
static bool IsValidViewMode(ViewMode mode);
static bool IsViewModeEnabled(ViewMode mode);
static bool IsCalculatorViewMode(ViewMode mode);
static bool IsGraphingCalculatorViewMode(ViewMode mode);
static bool IsDateCalculatorViewMode(ViewMode mode);
static bool IsConverterViewMode(ViewMode mode);
static void InitializeCategoryManifest(Windows::System::User ^ user);
static Platform::String ^ GetFriendlyName(ViewMode mode);
static Platform::String ^ GetNameResourceKey(ViewMode mode);
static CategoryGroupType GetGroupType(ViewMode mode);
@ -152,52 +176,9 @@ namespace CalculatorApp
static int GetIndexInGroup(ViewMode mode, CategoryGroupType type);
static int GetPosition(ViewMode mode);
// Virtual key related
static ViewMode GetViewModeForVirtualKey(MyVirtualKey virtualKey);
internal : NavCategory(
Platform::String ^ name,
Platform::String ^ automationName,
Platform::String ^ glyph,
Platform::String ^ accessKey,
Platform::String ^ mode,
ViewMode viewMode,
bool supportsNegative,
bool isEnabled)
: m_Name(name)
, m_AutomationName(automationName)
, m_Glyph(glyph)
, m_AccessKey(accessKey)
, m_modeString(mode)
, m_Mode(viewMode)
, m_SupportsNegative(supportsNegative)
, m_IsEnabled(isEnabled)
{
}
static std::vector<MyVirtualKey> GetCategoryAcceleratorKeys();
private:
static bool IsModeInCategoryGroup(ViewMode mode, CategoryGroupType groupType);
Platform::String ^ m_modeString;
};
[Windows::UI::Xaml::Data::Bindable] public ref class NavCategoryGroup sealed : public Windows::UI::Xaml::Data::INotifyPropertyChanged
{
public:
OBSERVABLE_OBJECT();
OBSERVABLE_PROPERTY_R(Platform::String ^, Name);
OBSERVABLE_PROPERTY_R(Platform::String ^, AutomationName);
OBSERVABLE_PROPERTY_R(CategoryGroupType, GroupType);
OBSERVABLE_PROPERTY_R(Windows::Foundation::Collections::IObservableVector<NavCategory ^> ^, Categories);
static Windows::Foundation::Collections::IObservableVector<NavCategoryGroup ^> ^ CreateMenuOptions();
internal : static NavCategoryGroup ^ CreateCalculatorCategory();
static NavCategoryGroup ^ CreateConverterCategory();
private:
NavCategoryGroup(const NavCategoryGroupInitializer& groupInitializer);
static void GetCategoryAcceleratorKeys(Windows::Foundation::Collections::IVector<MyVirtualKey> ^ resutls);
};
}
}

View file

@ -5,6 +5,8 @@
#include "NetworkManager.h"
using namespace CalculatorApp;
using namespace CalculatorApp::ViewModel;
using namespace CalculatorApp::ViewModel::Common;
using namespace Platform;
using namespace Windows::Networking::Connectivity;

View file

@ -3,7 +3,7 @@
#pragma once
namespace CalculatorApp
namespace CalculatorApp::ViewModel::Common
{
public
enum class NetworkAccessBehavior

View file

@ -2,7 +2,7 @@
// Licensed under the MIT License.
#pragma once
namespace CalculatorApp::Common
namespace CalculatorApp::ViewModel::Common
{
public
enum class NumberBase

View file

@ -0,0 +1,8 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pch.h"
#include "RadixType.h"
// export enum RadixType

View file

@ -0,0 +1,19 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
namespace CalculatorApp::ViewModel
{
namespace Common
{
// This is expected to be in same order as IDM_HEX, IDM_DEC, IDM_OCT, IDM_BIN
public enum class RadixType
{
Hex,
Decimal,
Octal,
Binary
};
}
}

View file

@ -7,7 +7,8 @@
#include "CalculatorButtonUser.h"
using namespace CalculatorApp;
using namespace CalculatorApp::Common;
using namespace CalculatorApp::ViewModel::Common;
using namespace CalculatorApp::ViewModel;
using namespace TraceLogging;
using namespace Concurrency;
using namespace std;
@ -78,7 +79,7 @@ namespace CalculatorApp
{
auto fields = ref new LoggingFields();
fields->AddString(StringReference(CALC_MODE), NavCategory::GetFriendlyName(mode));
fields->AddString(StringReference(CALC_MODE), NavCategoryStates::GetFriendlyName(mode));
fields->AddString(StringReference(L"VisualState"), state);
fields->AddBoolean(StringReference(L"IsAlwaysOnTop"), isAlwaysOnTop);
TraceLoggingCommon::GetInstance()->LogLevel2Event(StringReference(EVENT_NAME_VISUAL_STATE_CHANGED), fields);
@ -93,18 +94,17 @@ namespace CalculatorApp
}
auto fields = ref new LoggingFields();
fields->AddString(StringReference(CALC_MODE), NavCategory::GetFriendlyName(mode));
fields->AddString(StringReference(CALC_MODE), NavCategoryStates::GetFriendlyName(mode));
fields->AddUInt64(StringReference(L"NumOfOpenWindows"), currentWindowCount);
TraceLoggingCommon::GetInstance()->LogLevel2Event(StringReference(EVENT_NAME_WINDOW_ON_CREATED), fields);
}
void TraceLogger::LogModeChange(ViewMode mode)
{
if (NavCategory::IsValidViewMode(mode))
if (NavCategoryStates::IsValidViewMode(mode))
{
auto fields = ref new LoggingFields();
;
fields->AddString(StringReference(CALC_MODE), NavCategory::GetFriendlyName(mode));
fields->AddString(StringReference(CALC_MODE), NavCategoryStates::GetFriendlyName(mode));
TraceLoggingCommon::GetInstance()->LogLevel2Event(StringReference(EVENT_NAME_MODE_CHANGED), fields);
}
}
@ -112,7 +112,7 @@ namespace CalculatorApp
void TraceLogger::LogHistoryItemLoad(ViewMode mode, int historyListSize, int loadedIndex)
{
auto fields = ref new LoggingFields();
fields->AddString(StringReference(CALC_MODE), NavCategory::GetFriendlyName(mode));
fields->AddString(StringReference(CALC_MODE), NavCategoryStates::GetFriendlyName(mode));
fields->AddInt32(StringReference(L"HistoryListSize"), historyListSize);
fields->AddInt32(StringReference(L"HistoryItemIndex"), loadedIndex);
TraceLoggingCommon::GetInstance()->LogLevel2Event(StringReference(EVENT_NAME_HISTORY_ITEM_LOAD), fields);
@ -121,7 +121,7 @@ namespace CalculatorApp
void TraceLogger::LogMemoryItemLoad(ViewMode mode, int memoryListSize, int loadedIndex)
{
auto fields = ref new LoggingFields();
fields->AddString(StringReference(CALC_MODE), NavCategory::GetFriendlyName(mode));
fields->AddString(StringReference(CALC_MODE), NavCategoryStates::GetFriendlyName(mode));
fields->AddInt32(StringReference(L"MemoryListSize"), memoryListSize);
fields->AddInt32(StringReference(L"MemoryItemIndex"), loadedIndex);
TraceLoggingCommon::GetInstance()->LogLevel2Event(StringReference(EVENT_NAME_MEMORY_ITEM_LOAD), fields);
@ -130,7 +130,7 @@ namespace CalculatorApp
void TraceLogger::LogError(ViewMode mode, Platform::String ^ functionName, Platform::String ^ errorString)
{
auto fields = ref new LoggingFields();
fields->AddString(StringReference(CALC_MODE), NavCategory::GetFriendlyName(mode));
fields->AddString(StringReference(CALC_MODE), NavCategoryStates::GetFriendlyName(mode));
fields->AddString(StringReference(L"FunctionName"), functionName);
fields->AddString(StringReference(L"Message"), errorString);
TraceLoggingCommon::GetInstance()->LogLevel2Event(StringReference(EVENT_NAME_EXCEPTION), fields);
@ -139,7 +139,7 @@ namespace CalculatorApp
void TraceLogger::LogStandardException(ViewMode mode, wstring_view functionName, const exception& e)
{
auto fields = ref new LoggingFields();
fields->AddString(StringReference(CALC_MODE), NavCategory::GetFriendlyName(mode));
fields->AddString(StringReference(CALC_MODE), NavCategoryStates::GetFriendlyName(mode));
fields->AddString(StringReference(L"FunctionName"), StringReference(functionName.data()));
wstringstream exceptionMessage;
exceptionMessage << e.what();
@ -147,16 +147,21 @@ namespace CalculatorApp
TraceLoggingCommon::GetInstance()->LogLevel2Event(StringReference(EVENT_NAME_EXCEPTION), fields);
}
void TraceLogger::LogPlatformException(ViewMode mode, wstring_view functionName, Platform::Exception ^ e)
void TraceLogger::LogPlatformExceptionInfo(CalculatorApp::ViewModel::Common::ViewMode mode, Platform::String ^ functionName, Platform::String^ message, int hresult)
{
auto fields = ref new LoggingFields();
fields->AddString(StringReference(CALC_MODE), NavCategory::GetFriendlyName(mode));
fields->AddString(StringReference(L"FunctionName"), StringReference(functionName.data()));
fields->AddString(StringReference(L"Message"), e->Message);
fields->AddInt32(StringReference(L"HRESULT"), e->HResult);
fields->AddString(StringReference(CALC_MODE), NavCategoryStates::GetFriendlyName(mode));
fields->AddString(StringReference(L"FunctionName"), functionName);
fields->AddString(StringReference(L"Message"), message);
fields->AddInt32(StringReference(L"HRESULT"), hresult);
TraceLoggingCommon::GetInstance()->LogLevel2Event(StringReference(EVENT_NAME_EXCEPTION), fields);
}
void TraceLogger::LogPlatformException(ViewMode mode, Platform::String ^ functionName, Platform::Exception ^ e)
{
LogPlatformExceptionInfo(mode, functionName, e->Message, e->HResult);
}
void TraceLogger::UpdateButtonUsage(NumbersAndOperatorsEnum button, ViewMode mode)
{
// IsProgrammerMode, IsScientificMode, IsStandardMode and None are not actual buttons, so ignore them
@ -217,7 +222,7 @@ namespace CalculatorApp
Platform::String ^ buttonUsageString;
for (size_t i = 0; i < buttonLog.size(); i++)
{
buttonUsageString += NavCategory::GetFriendlyName(buttonLog[i].mode);
buttonUsageString += NavCategoryStates::GetFriendlyName(buttonLog[i].mode);
buttonUsageString += "|";
buttonUsageString += buttonLog[i].button.ToString();
buttonUsageString += "|";
@ -239,7 +244,7 @@ namespace CalculatorApp
{
const wchar_t* calculationType = AddSubtractMode ? L"AddSubtractMode" : L"DateDifferenceMode";
auto fields = ref new LoggingFields();
fields->AddString(StringReference(CALC_MODE), NavCategory::GetFriendlyName(ViewMode::Date));
fields->AddString(StringReference(CALC_MODE), NavCategoryStates::GetFriendlyName(ViewMode::Date));
fields->AddString(StringReference(L"CalculationType"), StringReference(calculationType));
TraceLoggingCommon::GetInstance()->LogLevel2Event(StringReference(EVENT_NAME_DATE_CALCULATION_MODE_USED), fields);
}
@ -247,7 +252,7 @@ namespace CalculatorApp
void TraceLogger::LogConverterInputReceived(ViewMode mode)
{
auto fields = ref new LoggingFields();
fields->AddString(StringReference(CALC_MODE), NavCategory::GetFriendlyName(mode));
fields->AddString(StringReference(CALC_MODE), NavCategoryStates::GetFriendlyName(mode));
TraceLoggingCommon::GetInstance()->LogLevel2Event(StringReference(EVENT_NAME_CONVERTER_INPUT_RECEIVED), fields);
}
@ -260,7 +265,7 @@ namespace CalculatorApp
void TraceLogger::LogInputPasted(ViewMode mode)
{
auto fields = ref new LoggingFields();
fields->AddString(StringReference(CALC_MODE), NavCategory::GetFriendlyName(mode));
fields->AddString(StringReference(CALC_MODE), NavCategoryStates::GetFriendlyName(mode));
TraceLoggingCommon::GetInstance()->LogLevel2Event(StringReference(EVENT_NAME_INPUT_PASTED), fields);
}

View file

@ -8,15 +8,15 @@
// A trace logging provider can only be instantiated and registered once per module.
// This class implements a singleton model ensure that only one instance is created.
namespace CalculatorApp
namespace CalculatorApp::ViewModel::Common
{
struct ButtonLog
{
public:
int count;
CalculatorApp::NumbersAndOperatorsEnum button;
CalculatorApp::Common::ViewMode mode;
ButtonLog(CalculatorApp::NumbersAndOperatorsEnum btn, CalculatorApp::Common::ViewMode vMode)
CalculatorApp::ViewModel::Common::NumbersAndOperatorsEnum button;
CalculatorApp::ViewModel::Common::ViewMode mode;
ButtonLog(CalculatorApp::ViewModel::Common::NumbersAndOperatorsEnum btn, CalculatorApp::ViewModel::Common::ViewMode vMode)
{
button = btn;
mode = vMode;
@ -62,20 +62,20 @@ namespace CalculatorApp
public:
static TraceLogger ^ GetInstance();
void LogModeChange(CalculatorApp::Common::ViewMode mode);
void LogHistoryItemLoad(CalculatorApp::Common::ViewMode mode, int historyListSize, int loadedIndex);
void LogMemoryItemLoad(CalculatorApp::Common::ViewMode mode, int memoryListSize, int loadedIndex);
void UpdateButtonUsage(CalculatorApp::NumbersAndOperatorsEnum button, CalculatorApp::Common::ViewMode mode);
void LogModeChange(CalculatorApp::ViewModel::Common::ViewMode mode);
void LogHistoryItemLoad(CalculatorApp::ViewModel::Common::ViewMode mode, int historyListSize, int loadedIndex);
void LogMemoryItemLoad(CalculatorApp::ViewModel::Common::ViewMode mode, int memoryListSize, int loadedIndex);
void UpdateButtonUsage(CalculatorApp::ViewModel::Common::NumbersAndOperatorsEnum button, CalculatorApp::ViewModel::Common::ViewMode mode);
void LogButtonUsage();
void LogDateCalculationModeUsed(bool AddSubtractMode);
void UpdateWindowCount(uint64 windowCount);
void DecreaseWindowCount();
bool IsWindowIdInLog(int windowId);
void LogVisualStateChanged(CalculatorApp::Common::ViewMode mode, Platform::String ^ state, bool isAlwaysOnTop);
void LogWindowCreated(CalculatorApp::Common::ViewMode mode, int windowId);
void LogConverterInputReceived(CalculatorApp::Common::ViewMode mode);
void LogVisualStateChanged(CalculatorApp::ViewModel::Common::ViewMode mode, Platform::String ^ state, bool isAlwaysOnTop);
void LogWindowCreated(CalculatorApp::ViewModel::Common::ViewMode mode, int windowId);
void LogConverterInputReceived(CalculatorApp::ViewModel::Common::ViewMode mode);
void LogNavBarOpened();
void LogError(CalculatorApp::Common::ViewMode mode, Platform::String ^ functionName, Platform::String ^ errorString);
void LogError(CalculatorApp::ViewModel::Common::ViewMode mode, Platform::String ^ functionName, Platform::String ^ errorString);
void LogShowHideButtonClicked(bool isHideButton);
void LogGraphButtonClicked(GraphButton buttonName, GraphButtonValue buttonValue);
void LogGraphLineStyleChanged(LineStyleType style);
@ -83,10 +83,12 @@ namespace CalculatorApp
void LogVariableSettingsChanged(Platform::String ^ setting);
void LogGraphSettingsChanged(GraphSettingsType settingsType, Platform::String ^ settingValue);
void LogGraphTheme(Platform::String ^ graphTheme);
void LogInputPasted(CalculatorApp::ViewModel::Common::ViewMode mode);
void LogPlatformExceptionInfo(CalculatorApp::ViewModel::Common::ViewMode mode, Platform::String ^ functionName, Platform::String ^ message, int hresult);
internal:
void LogStandardException(CalculatorApp::Common::ViewMode mode, std::wstring_view functionName, _In_ const std::exception& e);
void LogPlatformException(CalculatorApp::Common::ViewMode mode, std::wstring_view functionName, _In_ Platform::Exception ^ e);
void LogInputPasted(CalculatorApp::Common::ViewMode mode);
void LogPlatformException(CalculatorApp::ViewModel::Common::ViewMode mode, Platform::String ^ functionName, Platform::Exception ^ e);
void LogStandardException(CalculatorApp::ViewModel::Common::ViewMode mode, std::wstring_view functionName, _In_ const std::exception& e);
private:
// Create an instance of TraceLogger

View file

@ -6,13 +6,16 @@
//
#include "pch.h"
#include <winmeta.h>
#include "Utils.h"
#include "Common/AppResourceProvider.h"
#include "Common/ExpressionCommandSerializer.h"
#include "Common/ExpressionCommandDeserializer.h"
using namespace CalculatorApp;
using namespace CalculatorApp::Common;
using namespace CalculatorApp::ViewModel::Common;
using namespace concurrency;
using namespace Graphing::Renderer;
using namespace Platform;
@ -168,18 +171,20 @@ void Utils::TrimBack(wstring& value)
}).base(), value.end());
}
String^ Utils::EscapeHtmlSpecialCharacters(String^ originalString, shared_ptr<vector<wchar_t>> specialCharacters)
bool operator==(const Color& color1, const Color& color2)
{
return equal_to<Color>()(color1, color2);
}
bool operator!=(const Color& color1, const Color& color2)
{
return !(color1 == color2);
}
String^ CalculatorApp::ViewModel::Common::Utilities::EscapeHtmlSpecialCharacters(String^ originalString)
{
// Construct a default special characters if not provided.
if (specialCharacters == nullptr)
{
specialCharacters = make_shared<vector<wchar_t>>();
specialCharacters->push_back(L'&');
specialCharacters->push_back(L'\"');
specialCharacters->push_back(L'\'');
specialCharacters->push_back(L'<');
specialCharacters->push_back(L'>');
}
const std::vector<wchar_t> specialCharacters {L'&', L'\"', L'\'', L'<', L'>'};
bool replaceCharacters = false;
const wchar_t* pCh;
@ -189,7 +194,7 @@ String^ Utils::EscapeHtmlSpecialCharacters(String^ originalString, shared_ptr<ve
// If there isn't any special character, we simply return the original string
for (pCh = originalString->Data(); *pCh; pCh++)
{
if (std::find(specialCharacters->begin(), specialCharacters->end(), *pCh) != specialCharacters->end())
if (std::find(specialCharacters.begin(), specialCharacters.end(), *pCh) != specialCharacters.end())
{
replaceCharacters = true;
break;
@ -233,20 +238,15 @@ String^ Utils::EscapeHtmlSpecialCharacters(String^ originalString, shared_ptr<ve
return replaceCharacters ? replacementString : originalString;
}
bool operator==(const Color& color1, const Color& color2)
bool CalculatorApp::ViewModel::Common::Utilities::AreColorsEqual(Windows::UI::Color color1, Windows::UI::Color color2)
{
return equal_to<Color>()(color1, color2);
}
bool operator!=(const Color& color1, const Color& color2)
{
return !(color1 == color2);
return Utils::AreColorsEqual(color1, color2);
}
// This method calculates the luminance ratio between White and the given background color.
// The luminance is calculate using the RGB values and does not use the A value.
// White or Black is returned
SolidColorBrush ^ Utils::GetContrastColor(Color backgroundColor)
SolidColorBrush ^ CalculatorApp::ViewModel::Common::Utilities::GetContrastColor(Color backgroundColor)
{
auto luminance = 0.2126 * backgroundColor.R + 0.7152 * backgroundColor.G + 0.0722 * backgroundColor.B;
@ -257,3 +257,21 @@ SolidColorBrush ^ Utils::GetContrastColor(Color backgroundColor)
return static_cast<SolidColorBrush ^>(Application::Current->Resources->Lookup(L"BlackBrush"));
}
int CalculatorApp::ViewModel::Common::Utilities::GetWindowId()
{
return Utils::GetWindowId();
}
long long CalculatorApp::ViewModel::Common::Utilities::GetConst_WINEVENT_KEYWORD_RESPONSE_TIME()
{
return WINEVENT_KEYWORD_RESPONSE_TIME;
}
bool CalculatorApp::ViewModel::Common::Utilities::GetIntegratedDisplaySize(double* size)
{
if (SUCCEEDED(::GetIntegratedDisplaySize(size)))
return true;
return false;
}

View file

@ -168,11 +168,22 @@ public:
// The variable member generated by this macro should not be used in the class code, use the
// property getter instead.
#define COMMAND_FOR_METHOD(p, m) \
property Windows::UI::Xaml::Input::ICommand^ p {\
Windows::UI::Xaml::Input::ICommand^ get() {\
if (!donotuse_##p) {\
donotuse_##p = CalculatorApp::Common::MakeDelegate(this, &m);\
} return donotuse_##p; }} private: Windows::UI::Xaml::Input::ICommand^ donotuse_##p; \
property Windows::UI::Xaml::Input::ICommand ^ p \
{ \
Windows::UI::Xaml::Input::ICommand ^ get() \
{ \
if (!donotuse_##p) \
{ \
donotuse_##p = ref new CalculatorApp::ViewModel::Common::DelegateCommand( \
CalculatorApp::ViewModel::Common::MakeDelegateCommandHandler(this, &m) \
); \
} \
return donotuse_##p; \
} \
} \
\
private: \
Windows::UI::Xaml::Input::ICommand ^ donotuse_##p; \
\
public:
@ -398,10 +409,6 @@ namespace Utils
void Trim(std::wstring& value);
void TrimFront(std::wstring& value);
void TrimBack(std::wstring& value);
Platform::String ^ EscapeHtmlSpecialCharacters(Platform::String ^ originalString, std::shared_ptr<std::vector<wchar_t>> specialCharacters = nullptr);
Windows::UI::Xaml::Media::SolidColorBrush ^ GetContrastColor(Windows::UI::Color backgroundColor);
}
// This goes into the header to define the property, in the public: section of the class
@ -697,6 +704,22 @@ namespace CalculatorApp
return to;
}
namespace ViewModel::Common
{
// below utilities are intended to support interops between C# and C++/CX
// they can be removed if the entire codebase has been migrated to C#
public ref class Utilities sealed
{
public:
static Platform::String ^ EscapeHtmlSpecialCharacters(Platform::String ^ originalString);
static bool AreColorsEqual(Windows::UI::Color color1, Windows::UI::Color color2);
static Windows::UI::Xaml::Media::SolidColorBrush ^ GetContrastColor(Windows::UI::Color backgroundColor);
static int GetWindowId();
static long long GetConst_WINEVENT_KEYWORD_RESPONSE_TIME();
static bool GetIntegratedDisplaySize(double* size);
};
}
}
// There's no standard definition of equality for Windows::UI::Color structs.

View file

@ -11,11 +11,11 @@
#include "UnitConverterDataConstants.h"
using namespace CalculatorApp;
using namespace CalculatorApp::Common;
using namespace CalculatorApp::Common::LocalizationServiceProperties;
using namespace CalculatorApp::DataLoaders;
using namespace CalculatorApp::ViewModel::Common;
using namespace CalculatorApp::ViewModel::Common::LocalizationServiceProperties;
using namespace CalculatorApp::ViewModel::DataLoaders;
using namespace CalculatorApp::ViewModel;
using namespace CalculatorApp::ViewModel::CurrencyDataLoaderConstants;
using namespace CalculatorApp::ViewModel::DataLoaders::CurrencyDataLoaderConstants;
using namespace concurrency;
using namespace Platform;
using namespace std;
@ -69,7 +69,7 @@ static constexpr auto DEFAULT_TO_CURRENCY = L"EUR";
namespace CalculatorApp
{
namespace ViewModel
namespace ViewModel::DataLoaders
{
namespace UnitConverterResourceKeys
{
@ -188,10 +188,9 @@ void CurrencyDataLoader::ResetLoadStatus()
#pragma optimize("", off) // Turn off optimizations to work around DevDiv 393321
void CurrencyDataLoader::LoadData()
{
RegisterForNetworkBehaviorChanges();
if (!LoadFinished())
{
RegisterForNetworkBehaviorChanges();
create_task([this]() -> task<bool> {
vector<function<future<bool>()>> loadFunctions = {
[this]() { return TryLoadDataFromCacheAsync(); },
@ -241,7 +240,7 @@ unordered_map<UCM::Unit, UCM::ConversionData, UCM::UnitHash> CurrencyDataLoader:
bool CurrencyDataLoader::SupportsCategory(const UCM::Category& target)
{
static int currencyId = NavCategory::Serialize(ViewMode::Currency);
static int currencyId = NavCategoryStates::Serialize(ViewMode::Currency);
return target.id == currencyId;
}
@ -300,7 +299,7 @@ pair<wstring, wstring> CurrencyDataLoader::GetCurrencyRatioEquality(_In_ const U
double ratio = (iter2->second).ratio;
double rounded = RoundCurrencyRatio(ratio);
auto digit = LocalizationSettings::GetInstance().GetDigitSymbolFromEnUsDigit(L'1');
auto digit = LocalizationSettings::GetInstance()->GetDigitSymbolFromEnUsDigit(L'1');
auto digitSymbol = ref new String(&digit, 1);
auto roundedFormat = m_ratioFormatter->Format(rounded);

View file

@ -9,7 +9,7 @@
namespace CalculatorApp
{
namespace ViewModel
namespace ViewModel::DataLoaders
{
public
enum class CurrencyLoadStatus
@ -54,7 +54,9 @@ namespace CalculatorApp
class CurrencyDataLoader : public UCM::IConverterDataLoader, public UCM::ICurrencyConverterDataLoader
{
public:
CurrencyDataLoader(_In_ std::unique_ptr<CalculatorApp::DataLoaders::ICurrencyHttpClient> client, const wchar_t* overrideLanguage = nullptr);
CurrencyDataLoader(
_In_ std::unique_ptr<CalculatorApp::ViewModel::DataLoaders::ICurrencyHttpClient> client,
const wchar_t* overrideLanguage = nullptr);
~CurrencyDataLoader();
bool LoadFinished();
@ -82,7 +84,7 @@ namespace CalculatorApp
std::future<bool> TryLoadDataFromWebOverrideAsync() override;
// ICurrencyConverterDataLoader
void OnNetworkBehaviorChanged(CalculatorApp::NetworkAccessBehavior newBehavior);
void OnNetworkBehaviorChanged(CalculatorApp::ViewModel::Common::NetworkAccessBehavior newBehavior);
private:
void ResetLoadStatus();
@ -112,7 +114,7 @@ namespace CalculatorApp
private:
Platform::String ^ m_responseLanguage;
std::unique_ptr<CalculatorApp::DataLoaders::ICurrencyHttpClient> m_client;
std::unique_ptr<CalculatorApp::ViewModel::DataLoaders::ICurrencyHttpClient> m_client;
bool m_isRtlLanguage;
@ -130,8 +132,8 @@ namespace CalculatorApp
CurrencyLoadStatus m_loadStatus;
CalculatorApp::NetworkManager ^ m_networkManager;
CalculatorApp::NetworkAccessBehavior m_networkAccessBehavior;
CalculatorApp::ViewModel::Common::NetworkManager ^ m_networkManager;
CalculatorApp::ViewModel::Common::NetworkAccessBehavior m_networkAccessBehavior;
Windows::Foundation::EventRegistrationToken m_networkBehaviorToken;
bool m_meteredOverrideSet;
};

View file

@ -11,6 +11,7 @@
#endif
using namespace CalculatorApp::DataLoaders;
using namespace CalculatorApp::ViewModel::DataLoaders;
using namespace Platform;
using namespace std;
using namespace Windows::Foundation;

View file

@ -7,7 +7,7 @@
namespace CalculatorApp
{
namespace DataLoaders
namespace ViewModel::DataLoaders
{
class CurrencyHttpClient : public ICurrencyHttpClient
{

View file

@ -5,7 +5,7 @@
namespace CalculatorApp
{
namespace DataLoaders
namespace ViewModel::DataLoaders
{
class ICurrencyHttpClient
{

Some files were not shown because too many files have changed in this diff Show more