diff --git a/README.md b/README.md
index 308849f2..6ae32ab4 100644
--- a/README.md
+++ b/README.md
@@ -25,6 +25,8 @@ So you should install react-native-pdf and rn-fetch-blob
| progress-bar-android | | | | 1.0.3+ |
| progress-view | | | | 1.0.3+ |
+Currently, Windows support is partial. The rn-fetch-blob module is not yet available on Windows, only loading bundled PDFs is supported.
+
### Installation
```bash
@@ -86,6 +88,31 @@ react-native link react-native-pdf
+### Windows installation
+
+ Windows details
+
+- Open your solution in Visual Studio 2019 (eg. `windows\yourapp.sln`)
+- Right-click Solution icon in Solution Explorer > Add > Existing Project...
+- Add `node_modules\@react-native-community\progress-view\windows\progress-view\progress-view.vcxproj`
+- If running RNW 0.62: add `node_modules\react-native-pdf\windows\RCTPdf\RCTPdf.vcxproj`
+- Right-click main application project > Add > Reference...
+ - Select `progress-view` and in Solution Projects
+ - If running 0.62, also select `RCTPdf`
+- In app `pch.h` add `#include "winrt/progress-view.h"` and `#include "winrt/RCTPdf.h"`
+- In `App.cpp` add `PackageProviders().Append(winrt::progress-view::ReactPackageProvider());` before `InitializeComponent();`
+- If running RNW 0.62, also add `PackageProviders().Append(winrt::RCTPdf::ReactPackageProvider());`
+
+#### Bundling PDFs with the app
+To add a `test.pdf` like in the example add:
+```
+
+ true
+
+```
+in the app `.vcxproj` file, before ``.
+
+
### FAQ
FAQ details
@@ -270,55 +297,56 @@ const styles = StyleSheet.create({
### Configuration
-| Property | Type | Default | Description | iOS | Android | FirstRelease |
-| ------------- |:-------------:|:----------------:| ------------------- | ------| ------- | ------------ |
-| source | object | not null | PDF source like {uri:xxx, cache:false}. see the following for detail.| ✔ | ✔ | <3.0 |
-| page | number | 1 | initial page index | ✔ | ✔ | <3.0 |
-| scale | number | 1.0 | should minScale<=scale<=maxScale| ✔ | ✔ | <3.0 |
-| minScale | number | 1.0 | min scale| ✔ | ✔ | 5.0.5 |
-| maxScale | number | 3.0 | max scale| ✔ | ✔ | 5.0.5 |
-| horizontal | bool | false | draw page direction, if you want to listen the orientation change, you can use [[react-native-orientation-locker]](https://github.com/wonday/react-native-orientation-locker)| ✔ | ✔ | <3.0 |
-| fitWidth | bool | false | if true fit the width of view, can not use fitWidth=true together with scale| ✔ | ✔ | <3.0, abandoned from 3.0 |
-| fitPolicy | number | 2 | 0:fit width, 1:fit height, 2:fit both(default)| ✔ | ✔ | 3.0 |
-| spacing | number | 10 | the breaker size between pages| ✔ | ✔ | <3.0 |
-| password | string | "" | pdf password, if password error, will call OnError() with message "Password required or incorrect password." | ✔ | ✔ | <3.0 |
-| style | object | {backgroundColor:"#eee"} | support normal view style, you can use this to set border/spacing color... | ✔ | ✔ | <3.0 |
-| activityIndicator | Component | | when loading show it as an indicator, you can use your component| ✔ | ✔ | <3.0 |
-| activityIndicatorProps | object | {color:'#009900', progressTintColor:'#009900'} | activityIndicator props | ✔ | ✔ | 3.1 |
-| enableAntialiasing | bool | true | improve rendering a little bit on low-res screens, but maybe course some problem on Android 4.4, so add a switch | ✖ | ✔ | <3.0 |
-| enablePaging | bool | false | only show one page in screen | ✔ | ✔ | 5.0.1 |
-| enableRTL | bool | false | scroll page as "page3, page2, page1" | ✔ | ✖ | 5.0.1 |
-| enableAnnotationRendering | bool | true | enable rendering annotation, notice:iOS only support initial setting,not support realtime changing | ✔ | ✔ | 5.0.3 |
-| trustAllCerts | bool | true | Allow connections to servers with self-signed certification | ✔ | ✔ | 6.0.? |
-| singlePage | bool | false | Only show first page, useful for thumbnail views | ✔ | ✔ | 6.1.2 |
-| onLoadProgress | function(percent) | null | callback when loading, return loading progress (0-1) | ✔ | ✔ | <3.0 |
-| onLoadComplete | function(numberOfPages, path, {width, height}, tableContents) | null | callback when pdf load completed, return total page count, pdf local/cache path, {width,height} and table of contents | ✔ | ✔ | <3.0 |
-| onPageChanged | function(page,numberOfPages) | null | callback when page changed ,return current page and total page count | ✔ | ✔ | <3.0 |
-| onError | function(error) | null | callback when error happened | ✔ | ✔ | <3.0 |
-| onPageSingleTap | function(page) | null | callback when page was single tapped | ✔ | ✔ | 3.0 |
-| onScaleChanged | function(scale) | null | callback when scale page | ✔ | ✔ | 3.0 |
-| onPressLink | function(uri) | null | callback when link tapped | ✔ | ✔ | 6.0.0 |
+| Property | Type | Default | Description | iOS | Android | Windows | FirstRelease |
+| ------------- |:-------------:|:----------------:| ------------------- | ------| ------- | ------- | ------------ |
+| source | object | not null | PDF source like {uri:xxx, cache:false}. see the following for detail.| ✔ | ✔ | partial | <3.0 |
+| page | number | 1 | initial page index | ✔ | ✔ | ✔ | <3.0 |
+| scale | number | 1.0 | should minScale<=scale<=maxScale| ✔ | ✔ | ✔ | <3.0 |
+| minScale | number | 1.0 | min scale| ✔ | ✔ | ✔ | 5.0.5 |
+| maxScale | number | 3.0 | max scale| ✔ | ✔ | ✔ | 5.0.5 |
+| horizontal | bool | false | draw page direction, if you want to listen the orientation change, you can use [[react-native-orientation-locker]](https://github.com/wonday/react-native-orientation-locker)| ✔ | ✔ | ✔ | <3.0 |
+| fitWidth | bool | false | if true fit the width of view, can not use fitWidth=true together with scale| ✔ | ✔ | ✔ | <3.0, abandoned from 3.0 |
+| fitPolicy | number | 2 | 0:fit width, 1:fit height, 2:fit both(default)| ✔ | ✔ | ✔ | 3.0 |
+| spacing | number | 10 | the breaker size between pages| ✔ | ✔ | ✔ | <3.0 |
+| password | string | "" | pdf password, if password error, will call OnError() with message "Password required or incorrect password." | ✔ | ✔ | ✔ | <3.0 |
+| style | object | {backgroundColor:"#eee"} | support normal view style, you can use this to set border/spacing color... | ✔ | ✔ | ✔ | <3.0 |
+| activityIndicator | Component | | when loading show it as an indicator, you can use your component| ✔ | ✔ | ✖ | <3.0 |
+| activityIndicatorProps | object | {color:'#009900', progressTintColor:'#009900'} | activityIndicator props | ✔ | ✔ | ✖ | 3.1 |
+| enableAntialiasing | bool | true | improve rendering a little bit on low-res screens, but maybe course some problem on Android 4.4, so add a switch | ✖ | ✔ | ✖ | <3.0 |
+| enablePaging | bool | false | only show one page in screen | ✔ | ✔ | ✔ | 5.0.1 |
+| enableRTL | bool | false | scroll page as "page3, page2, page1" | ✔ | ✖ | ✔ | 5.0.1 |
+| enableAnnotationRendering | bool | true | enable rendering annotation, notice:iOS only support initial setting,not support realtime changing | ✔ | ✔ | ✖ | 5.0.3 |
+| trustAllCerts | bool | true | Allow connections to servers with self-signed certification | ✔ | ✔ | ✖ | 6.0.? |
+| singlePage | bool | false | Only show first page, useful for thumbnail views | ✔ | ✔ | ✔ | 6.1.2 |
+| onLoadProgress | function(percent) | null | callback when loading, return loading progress (0-1) | ✔ | ✔ | ✖ | <3.0 |
+| onLoadComplete | function(numberOfPages, path, {width, height}, tableContents) | null | callback when pdf load completed, return total page count, pdf local/cache path, {width,height} and table of contents | ✔ | ✔ | ✔ but without tableContents | <3.0 |
+| onPageChanged | function(page,numberOfPages) | null | callback when page changed ,return current page and total page count | ✔ | ✔ | ✔ | <3.0 |
+| onError | function(error) | null | callback when error happened | ✔ | ✔ | ✔ | <3.0 |
+| onPageSingleTap | function(page) | null | callback when page was single tapped | ✔ | ✔ | ✔ | 3.0 |
+| onScaleChanged | function(scale) | null | callback when scale page | ✔ | ✔ | ✔ | 3.0 |
+| onPressLink | function(uri) | null | callback when link tapped | ✔ | ✔ | ✖ | 6.0.0 |
#### parameters of source
-| parameter | Description | default | iOS | Android |
-| ------------ | ----------- | ------- | --- | ------- |
-| uri | pdf source, see the forllowing for detail.| required | ✔ | ✔ |
-| cache | use cache or not | false | ✔ | ✔ |
-| expiration | cache file expired seconds (0 is not expired) | 0 | ✔ | ✔ |
-| method | request method when uri is a url | "GET" | ✔ | ✔ |
-| headers | request headers when uri is a url | {} | ✔ | ✔ |
+| parameter | Description | default | iOS | Android | Windows |
+| ------------ | ----------- | ------- | --- | ------- | ------- |
+| uri | pdf source, see the forllowing for detail.| required | ✔ | ✔ | ✔ |
+| cache | use cache or not | false | ✔ | ✔ | ✖ |
+| expiration | cache file expired seconds (0 is not expired) | 0 | ✔ | ✔ | ✖ |
+| method | request method when uri is a url | "GET" | ✔ | ✔ | ✖ |
+| headers | request headers when uri is a url | {} | ✔ | ✔ | ✖ |
#### types of source.uri
-| Usage | Description | iOS | Android |
-| ------------ | ----------- | --- | ------- |
-| `{uri:"http://xxx/xxx.pdf"}` | load pdf from a url | ✔ | ✔ |
-| `{require("./test.pdf")}` | load pdf relate to js file (do not need add by xcode) | ✔ | ✖ |
-| `{uri:"bundle-assets://path/to/xxx.pdf"}` | load pdf from assets, the file should be at android/app/src/main/assets/path/to/xxx.pdf | ✖ | ✔ |
-| `{uri:"bundle-assets://xxx.pdf"}` | load pdf from assets, you must add pdf to project by xcode. this does not support folder. | ✔ | ✖ |
-| `{uri:"data:application/pdf;base64,JVBERi0xLjcKJc..."}` | load pdf from base64 string | ✔ | ✔ |
-| `{uri:"file:///absolute/path/to/xxx.pdf"}` | load pdf from local file system | ✔ | ✔ |
+| Usage | Description | iOS | Android | Windows |
+| ------------ | ----------- | --- | ------- | ------- |
+| `{uri:"http://xxx/xxx.pdf"}` | load pdf from a url | ✔ | ✔ | ✖ |
+| `{require("./test.pdf")}` | load pdf relate to js file (do not need add by xcode) | ✔ | ✖ | ✖ |
+| `{uri:"bundle-assets://path/to/xxx.pdf"}` | load pdf from assets, the file should be at android/app/src/main/assets/path/to/xxx.pdf | ✖ | ✔ | ✖ |
+| `{uri:"bundle-assets://xxx.pdf"}` | load pdf from assets, you must add pdf to project by xcode. this does not support folder. | ✔ | ✖ | ✖ |
+| `{uri:"data:application/pdf;base64,JVBERi0xLjcKJc..."}` | load pdf from base64 string | ✔ | ✔ | ✖ |
+| `{uri:"file:///absolute/path/to/xxx.pdf"}` | load pdf from local file system | ✔ | ✔ | ✔ |
+| `{uri:"ms-appx:///xxx.pdf"}}` | load pdf bundled with UWP app | ✖ | ✖ | ✔ |
### Methods
diff --git a/example/.gitignore b/example/.gitignore
index 828cc884..f3bcfdf4 100644
--- a/example/.gitignore
+++ b/example/.gitignore
@@ -57,3 +57,67 @@ buck-out/
# CocoaPods
/ios/Pods/
+
+# OSX
+#
+.DS_Store
+
+# Xcode
+#
+build/
+*.pbxuser
+!default.pbxuser
+*.mode1v3
+!default.mode1v3
+*.mode2v3
+!default.mode2v3
+*.perspectivev3
+!default.perspectivev3
+xcuserdata
+*.xccheckout
+*.moved-aside
+DerivedData
+*.hmap
+*.ipa
+*.xcuserstate
+
+# Android/IntelliJ
+#
+build/
+.idea
+.gradle
+local.properties
+*.iml
+
+# node.js
+#
+node_modules/
+npm-debug.log
+yarn-error.log
+
+# BUCK
+buck-out/
+\.buckd/
+*.keystore
+!debug.keystore
+
+# fastlane
+#
+# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
+# screenshots whenever they are needed.
+# For more information about the recommended setup visit:
+# https://docs.fastlane.tools/best-practices/source-control/
+
+*/fastlane/report.xml
+*/fastlane/Preview.html
+*/fastlane/screenshots
+
+# Bundle artifact
+*.jsbundle
+
+# CocoaPods
+/ios/Pods/
+
+# VS
+*.binlog
+*.ProjectImports.zip
diff --git a/example/PDFExample.js b/example/PDFExample.js
index e9dc4048..d9ef4980 100644
--- a/example/PDFExample.js
+++ b/example/PDFExample.js
@@ -83,6 +83,7 @@ export default class PDFExample extends React.Component {
render() {
let source = {uri:'http://samples.leanpub.com/thereactnativebook-sample.pdf',cache:true};
+ //let source = {uri: 'ms-appx:///test.pdf'}
//let source = require('./test.pdf'); // ios only
//let source = {uri:'bundle-assets://test.pdf'};
diff --git a/example/metro.config.js b/example/metro.config.js
index 13a96421..1b710a4d 100644
--- a/example/metro.config.js
+++ b/example/metro.config.js
@@ -4,8 +4,20 @@
*
* @format
*/
+const path = require('path');
+const blacklist = require('metro-config/src/defaults/blacklist');
module.exports = {
+ resolver: {
+ blacklistRE: blacklist([
+ // This stops "react-native run-windows" from causing the metro server to crash if its already running
+ new RegExp(
+ `${path.resolve(__dirname, 'windows').replace(/[/\\]/g, '/')}.*`,
+ ),
+ // This prevents "react-native run-windows" from hitting: EBUSY: resource busy or locked, open msbuild.ProjectImports.zip
+ /.*\.ProjectImports\.zip/,
+ ]),
+ },
transformer: {
getTransformOptions: async () => ({
transform: {
diff --git a/example/package.json b/example/package.json
index 0595815c..173c3b15 100644
--- a/example/package.json
+++ b/example/package.json
@@ -20,10 +20,11 @@
"url": "https://github.com/wonday/react-native-pdf/issues"
},
"dependencies": {
- "react": "16.8.6",
- "react-native": "0.60.4",
+ "react": "16.13.1",
+ "react-native": "0.63.2",
"react-native-orientation-locker": "^1.1.6",
- "react-native-pdf": "github:wonday/react-native-pdf#master",
+ "react-native-pdf": "file:../",
+ "react-native-windows": "^0.63.11",
"rn-fetch-blob": "^0.10.16"
},
"devDependencies": {
diff --git a/example/windows/.gitignore b/example/windows/.gitignore
new file mode 100644
index 00000000..4ea0c7b5
--- /dev/null
+++ b/example/windows/.gitignore
@@ -0,0 +1,92 @@
+*AppPackages*
+*BundleArtifacts*
+
+#OS junk files
+[Tt]humbs.db
+*.DS_Store
+
+#Visual Studio files
+*.[Oo]bj
+*.user
+*.aps
+*.pch
+*.vspscc
+*.vssscc
+*_i.c
+*_p.c
+*.ncb
+*.suo
+*.tlb
+*.tlh
+*.bak
+*.[Cc]ache
+*.ilk
+*.log
+*.lib
+*.sbr
+*.sdf
+*.opensdf
+*.opendb
+*.unsuccessfulbuild
+ipch/
+[Oo]bj/
+[Bb]in
+[Dd]ebug*/
+[Rr]elease*/
+Ankh.NoLoad
+
+# Visual C++ cache files
+ipch/
+*.aps
+*.ncb
+*.opendb
+*.opensdf
+*.sdf
+*.cachefile
+*.VC.db
+*.VC.VC.opendb
+
+#MonoDevelop
+*.pidb
+*.userprefs
+
+#Tooling
+_ReSharper*/
+*.resharper
+[Tt]est[Rr]esult*
+*.sass-cache
+
+#Project files
+[Bb]uild/
+
+#Subversion files
+.svn
+
+# Office Temp Files
+~$*
+
+# vim Temp Files
+*~
+
+#NuGet
+packages/
+*.nupkg
+
+#ncrunch
+*ncrunch*
+*crunch*.local.xml
+
+# visual studio database projects
+*.dbmdl
+
+#Test files
+*.testsettings
+
+#Other files
+*.DotSettings
+.vs/
+*project.lock.json
+
+#Files generated by the VS build
+**/Generated Files/**
+
diff --git a/example/windows/PDFExample.sln b/example/windows/PDFExample.sln
new file mode 100644
index 00000000..4116b9d5
--- /dev/null
+++ b/example/windows/PDFExample.sln
@@ -0,0 +1,264 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.29215.179
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PDFExample", "PDFExample\PDFExample.vcxproj", "{95F9323C-1039-4B6A-B69E-A9EFDDFEFB54}"
+ ProjectSection(ProjectDependencies) = postProject
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136} = {F7D32BD0-2749-483E-9A0D-1635EF7E3136}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Folly", "..\node_modules\react-native-windows\Folly\Folly.vcxproj", "{A990658C-CE31-4BCC-976F-0FC6B1AF693D}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ReactCommon", "..\node_modules\react-native-windows\ReactCommon\ReactCommon.vcxproj", "{A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}"
+ ProjectSection(ProjectDependencies) = postProject
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D} = {A990658C-CE31-4BCC-976F-0FC6B1AF693D}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Chakra", "..\node_modules\react-native-windows\Chakra\Chakra.vcxitems", "{C38970C0-5FBF-4D69-90D8-CBAC225AE895}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.ReactNative", "..\node_modules\react-native-windows\Microsoft.ReactNative\Microsoft.ReactNative.vcxproj", "{F7D32BD0-2749-483E-9A0D-1635EF7E3136}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "JSI.Shared", "..\node_modules\react-native-windows\JSI\Shared\JSI.Shared.vcxitems", "{0CC28589-39E4-4288-B162-97B959F8B843}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "JSI.Universal", "..\node_modules\react-native-windows\JSI\Universal\JSI.Universal.vcxproj", "{A62D504A-16B8-41D2-9F19-E2E86019E5E4}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.ReactNative.Cxx", "..\node_modules\react-native-windows\Microsoft.ReactNative.Cxx\Microsoft.ReactNative.Cxx.vcxitems", "{DA8B35B3-DA00-4B02-BDE6-6A397B3FD46B}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Common", "..\node_modules\react-native-windows\Common\Common.vcxproj", "{FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ReactNative", "ReactNative", "{5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.ReactNative.Shared", "..\node_modules\react-native-windows\Shared\Shared.vcxitems", "{2049DBE9-8D13-42C9-AE4B-413AE38FFFD0}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Mso", "..\node_modules\react-native-windows\Mso\Mso.vcxitems", "{84E05BFA-CBAF-4F0D-BFB6-4CE85742A57E}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Include", "..\node_modules\react-native-windows\include\Include.vcxitems", "{EF074BA1-2D54-4D49-A28E-5E040B47CD2E}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.ReactNative.Managed", "..\node_modules\react-native-windows\Microsoft.ReactNative.Managed\Microsoft.ReactNative.Managed.csproj", "{F2824844-CE15-4242-9420-308923CD76C3}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.ReactNative.Managed.CodeGen", "..\node_modules\react-native-windows\Microsoft.ReactNative.Managed.CodeGen\Microsoft.ReactNative.Managed.CodeGen.csproj", "{ADED4FBE-887D-4271-AF24-F0823BCE7961}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RCTPdf", "..\node_modules\react-native-pdf\windows\RCTPdf\RCTPdf.vcxproj", "{03B8503F-F40D-4013-829C-71B304537D90}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "progress-view", "..\node_modules\@react-native-community\progress-view\windows\progress-view\progress-view.vcxproj", "{CA54A654-5E81-44DC-AF3F-CF55EF5B493A}"
+EndProject
+Global
+ GlobalSection(SharedMSBuildProjectFiles) = preSolution
+ ..\node_modules\react-native-windows\JSI\Shared\JSI.Shared.vcxitems*{0cc28589-39e4-4288-b162-97b959f8b843}*SharedItemsImports = 9
+ ..\node_modules\react-native-windows\Shared\Shared.vcxitems*{2049dbe9-8d13-42c9-ae4b-413ae38fffd0}*SharedItemsImports = 9
+ ..\node_modules\react-native-windows\Mso\Mso.vcxitems*{84e05bfa-cbaf-4f0d-bfb6-4ce85742a57e}*SharedItemsImports = 9
+ ..\node_modules\react-native-windows\JSI\Shared\JSI.Shared.vcxitems*{a62d504a-16b8-41d2-9f19-e2e86019e5e4}*SharedItemsImports = 4
+ ..\node_modules\react-native-windows\Chakra\Chakra.vcxitems*{c38970c0-5fbf-4d69-90d8-cbac225ae895}*SharedItemsImports = 9
+ ..\node_modules\react-native-windows\Microsoft.ReactNative.Cxx\Microsoft.ReactNative.Cxx.vcxitems*{ca54a654-5e81-44dc-af3f-cf55ef5b493a}*SharedItemsImports = 4
+ ..\node_modules\react-native-windows\Microsoft.ReactNative.Cxx\Microsoft.ReactNative.Cxx.vcxitems*{da8b35b3-da00-4b02-bde6-6a397b3fd46b}*SharedItemsImports = 9
+ ..\node_modules\react-native-windows\include\Include.vcxitems*{ef074ba1-2d54-4d49-a28e-5e040b47cd2e}*SharedItemsImports = 9
+ ..\node_modules\react-native-windows\Chakra\Chakra.vcxitems*{f7d32bd0-2749-483e-9a0d-1635ef7e3136}*SharedItemsImports = 4
+ ..\node_modules\react-native-windows\Microsoft.ReactNative.Cxx\Microsoft.ReactNative.Cxx.vcxitems*{f7d32bd0-2749-483e-9a0d-1635ef7e3136}*SharedItemsImports = 4
+ ..\node_modules\react-native-windows\Mso\Mso.vcxitems*{f7d32bd0-2749-483e-9a0d-1635ef7e3136}*SharedItemsImports = 4
+ ..\node_modules\react-native-windows\Shared\Shared.vcxitems*{f7d32bd0-2749-483e-9a0d-1635ef7e3136}*SharedItemsImports = 4
+ EndGlobalSection
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|ARM = Debug|ARM
+ Debug|ARM64 = Debug|ARM64
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|ARM = Release|ARM
+ Release|ARM64 = Release|ARM64
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {95F9323C-1039-4B6A-B69E-A9EFDDFEFB54}.Debug|ARM.ActiveCfg = Debug|ARM
+ {95F9323C-1039-4B6A-B69E-A9EFDDFEFB54}.Debug|ARM.Build.0 = Debug|ARM
+ {95F9323C-1039-4B6A-B69E-A9EFDDFEFB54}.Debug|ARM.Deploy.0 = Debug|ARM
+ {95F9323C-1039-4B6A-B69E-A9EFDDFEFB54}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {95F9323C-1039-4B6A-B69E-A9EFDDFEFB54}.Debug|ARM64.Build.0 = Debug|ARM64
+ {95F9323C-1039-4B6A-B69E-A9EFDDFEFB54}.Debug|ARM64.Deploy.0 = Debug|ARM64
+ {95F9323C-1039-4B6A-B69E-A9EFDDFEFB54}.Debug|x64.ActiveCfg = Debug|x64
+ {95F9323C-1039-4B6A-B69E-A9EFDDFEFB54}.Debug|x64.Build.0 = Debug|x64
+ {95F9323C-1039-4B6A-B69E-A9EFDDFEFB54}.Debug|x64.Deploy.0 = Debug|x64
+ {95F9323C-1039-4B6A-B69E-A9EFDDFEFB54}.Debug|x86.ActiveCfg = Debug|Win32
+ {95F9323C-1039-4B6A-B69E-A9EFDDFEFB54}.Debug|x86.Build.0 = Debug|Win32
+ {95F9323C-1039-4B6A-B69E-A9EFDDFEFB54}.Debug|x86.Deploy.0 = Debug|Win32
+ {95F9323C-1039-4B6A-B69E-A9EFDDFEFB54}.Release|ARM.ActiveCfg = Release|ARM
+ {95F9323C-1039-4B6A-B69E-A9EFDDFEFB54}.Release|ARM.Build.0 = Release|ARM
+ {95F9323C-1039-4B6A-B69E-A9EFDDFEFB54}.Release|ARM.Deploy.0 = Release|ARM
+ {95F9323C-1039-4B6A-B69E-A9EFDDFEFB54}.Release|ARM64.ActiveCfg = Release|ARM64
+ {95F9323C-1039-4B6A-B69E-A9EFDDFEFB54}.Release|ARM64.Build.0 = Release|ARM64
+ {95F9323C-1039-4B6A-B69E-A9EFDDFEFB54}.Release|ARM64.Deploy.0 = Release|ARM64
+ {95F9323C-1039-4B6A-B69E-A9EFDDFEFB54}.Release|x64.ActiveCfg = Release|x64
+ {95F9323C-1039-4B6A-B69E-A9EFDDFEFB54}.Release|x64.Build.0 = Release|x64
+ {95F9323C-1039-4B6A-B69E-A9EFDDFEFB54}.Release|x64.Deploy.0 = Release|x64
+ {95F9323C-1039-4B6A-B69E-A9EFDDFEFB54}.Release|x86.ActiveCfg = Release|Win32
+ {95F9323C-1039-4B6A-B69E-A9EFDDFEFB54}.Release|x86.Build.0 = Release|Win32
+ {95F9323C-1039-4B6A-B69E-A9EFDDFEFB54}.Release|x86.Deploy.0 = Release|Win32
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|ARM.ActiveCfg = Debug|ARM
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|ARM.Build.0 = Debug|ARM
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|ARM64.Build.0 = Debug|ARM64
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x64.ActiveCfg = Debug|x64
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x64.Build.0 = Debug|x64
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x86.ActiveCfg = Debug|Win32
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x86.Build.0 = Debug|Win32
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|ARM.ActiveCfg = Release|ARM
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|ARM.Build.0 = Release|ARM
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|ARM64.ActiveCfg = Release|ARM64
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|ARM64.Build.0 = Release|ARM64
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x64.ActiveCfg = Release|x64
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x64.Build.0 = Release|x64
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x86.ActiveCfg = Release|Win32
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x86.Build.0 = Release|Win32
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|ARM.ActiveCfg = Debug|ARM
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|ARM.Build.0 = Debug|ARM
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|ARM64.Build.0 = Debug|ARM64
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|x64.ActiveCfg = Debug|x64
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|x64.Build.0 = Debug|x64
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|x86.ActiveCfg = Debug|Win32
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|x86.Build.0 = Debug|Win32
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Release|ARM.ActiveCfg = Release|ARM
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Release|ARM.Build.0 = Release|ARM
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Release|ARM64.ActiveCfg = Release|ARM64
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Release|ARM64.Build.0 = Release|ARM64
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Release|x64.ActiveCfg = Release|x64
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Release|x64.Build.0 = Release|x64
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Release|x86.ActiveCfg = Release|Win32
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Release|x86.Build.0 = Release|Win32
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Debug|ARM.ActiveCfg = Debug|ARM
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Debug|ARM.Build.0 = Debug|ARM
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Debug|ARM64.Build.0 = Debug|ARM64
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Debug|x64.ActiveCfg = Debug|x64
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Debug|x64.Build.0 = Debug|x64
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Debug|x86.ActiveCfg = Debug|Win32
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Debug|x86.Build.0 = Debug|Win32
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Release|ARM.ActiveCfg = Release|ARM
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Release|ARM.Build.0 = Release|ARM
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Release|ARM64.ActiveCfg = Release|ARM64
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Release|ARM64.Build.0 = Release|ARM64
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Release|x64.ActiveCfg = Release|x64
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Release|x64.Build.0 = Release|x64
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Release|x86.ActiveCfg = Release|Win32
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Release|x86.Build.0 = Release|Win32
+ {A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Debug|ARM.ActiveCfg = Debug|ARM
+ {A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Debug|ARM.Build.0 = Debug|ARM
+ {A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Debug|ARM64.Build.0 = Debug|ARM64
+ {A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Debug|x64.ActiveCfg = Debug|x64
+ {A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Debug|x64.Build.0 = Debug|x64
+ {A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Debug|x86.ActiveCfg = Debug|Win32
+ {A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Debug|x86.Build.0 = Debug|Win32
+ {A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Release|ARM.ActiveCfg = Release|ARM
+ {A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Release|ARM.Build.0 = Release|ARM
+ {A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Release|ARM64.ActiveCfg = Release|ARM64
+ {A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Release|ARM64.Build.0 = Release|ARM64
+ {A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Release|x64.ActiveCfg = Release|x64
+ {A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Release|x64.Build.0 = Release|x64
+ {A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Release|x86.ActiveCfg = Release|Win32
+ {A62D504A-16B8-41D2-9F19-E2E86019E5E4}.Release|x86.Build.0 = Release|Win32
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Debug|ARM.ActiveCfg = Debug|ARM
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Debug|ARM.Build.0 = Debug|ARM
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Debug|ARM64.Build.0 = Debug|ARM64
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Debug|x64.ActiveCfg = Debug|x64
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Debug|x64.Build.0 = Debug|x64
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Debug|x86.ActiveCfg = Debug|Win32
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Debug|x86.Build.0 = Debug|Win32
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|ARM.ActiveCfg = Release|ARM
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|ARM.Build.0 = Release|ARM
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|ARM64.ActiveCfg = Release|ARM64
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|ARM64.Build.0 = Release|ARM64
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|x64.ActiveCfg = Release|x64
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|x64.Build.0 = Release|x64
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|x86.ActiveCfg = Release|Win32
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|x86.Build.0 = Release|Win32
+ {F2824844-CE15-4242-9420-308923CD76C3}.Debug|ARM.ActiveCfg = Debug|ARM
+ {F2824844-CE15-4242-9420-308923CD76C3}.Debug|ARM.Build.0 = Debug|ARM
+ {F2824844-CE15-4242-9420-308923CD76C3}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {F2824844-CE15-4242-9420-308923CD76C3}.Debug|ARM64.Build.0 = Debug|ARM64
+ {F2824844-CE15-4242-9420-308923CD76C3}.Debug|x64.ActiveCfg = Debug|x64
+ {F2824844-CE15-4242-9420-308923CD76C3}.Debug|x64.Build.0 = Debug|x64
+ {F2824844-CE15-4242-9420-308923CD76C3}.Debug|x86.ActiveCfg = Debug|x86
+ {F2824844-CE15-4242-9420-308923CD76C3}.Debug|x86.Build.0 = Debug|x86
+ {F2824844-CE15-4242-9420-308923CD76C3}.Release|ARM.ActiveCfg = Release|ARM
+ {F2824844-CE15-4242-9420-308923CD76C3}.Release|ARM.Build.0 = Release|ARM
+ {F2824844-CE15-4242-9420-308923CD76C3}.Release|ARM64.ActiveCfg = Release|ARM64
+ {F2824844-CE15-4242-9420-308923CD76C3}.Release|ARM64.Build.0 = Release|ARM64
+ {F2824844-CE15-4242-9420-308923CD76C3}.Release|x64.ActiveCfg = Release|x64
+ {F2824844-CE15-4242-9420-308923CD76C3}.Release|x64.Build.0 = Release|x64
+ {F2824844-CE15-4242-9420-308923CD76C3}.Release|x86.ActiveCfg = Release|x86
+ {F2824844-CE15-4242-9420-308923CD76C3}.Release|x86.Build.0 = Release|x86
+ {ADED4FBE-887D-4271-AF24-F0823BCE7961}.Debug|ARM.ActiveCfg = Debug|ARM
+ {ADED4FBE-887D-4271-AF24-F0823BCE7961}.Debug|ARM.Build.0 = Debug|ARM
+ {ADED4FBE-887D-4271-AF24-F0823BCE7961}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {ADED4FBE-887D-4271-AF24-F0823BCE7961}.Debug|ARM64.Build.0 = Debug|ARM64
+ {ADED4FBE-887D-4271-AF24-F0823BCE7961}.Debug|x64.ActiveCfg = Debug|x64
+ {ADED4FBE-887D-4271-AF24-F0823BCE7961}.Debug|x64.Build.0 = Debug|x64
+ {ADED4FBE-887D-4271-AF24-F0823BCE7961}.Debug|x86.ActiveCfg = Debug|x86
+ {ADED4FBE-887D-4271-AF24-F0823BCE7961}.Debug|x86.Build.0 = Debug|x86
+ {ADED4FBE-887D-4271-AF24-F0823BCE7961}.Release|ARM.ActiveCfg = Release|ARM
+ {ADED4FBE-887D-4271-AF24-F0823BCE7961}.Release|ARM.Build.0 = Release|ARM
+ {ADED4FBE-887D-4271-AF24-F0823BCE7961}.Release|ARM64.ActiveCfg = Release|ARM64
+ {ADED4FBE-887D-4271-AF24-F0823BCE7961}.Release|ARM64.Build.0 = Release|ARM64
+ {ADED4FBE-887D-4271-AF24-F0823BCE7961}.Release|x64.ActiveCfg = Release|x64
+ {ADED4FBE-887D-4271-AF24-F0823BCE7961}.Release|x64.Build.0 = Release|x64
+ {ADED4FBE-887D-4271-AF24-F0823BCE7961}.Release|x86.ActiveCfg = Release|x86
+ {ADED4FBE-887D-4271-AF24-F0823BCE7961}.Release|x86.Build.0 = Release|x86
+ {03B8503F-F40D-4013-829C-71B304537D90}.Debug|ARM.ActiveCfg = Debug|ARM
+ {03B8503F-F40D-4013-829C-71B304537D90}.Debug|ARM.Build.0 = Debug|ARM
+ {03B8503F-F40D-4013-829C-71B304537D90}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {03B8503F-F40D-4013-829C-71B304537D90}.Debug|ARM64.Build.0 = Debug|ARM64
+ {03B8503F-F40D-4013-829C-71B304537D90}.Debug|x64.ActiveCfg = Debug|x64
+ {03B8503F-F40D-4013-829C-71B304537D90}.Debug|x64.Build.0 = Debug|x64
+ {03B8503F-F40D-4013-829C-71B304537D90}.Debug|x86.ActiveCfg = Debug|Win32
+ {03B8503F-F40D-4013-829C-71B304537D90}.Debug|x86.Build.0 = Debug|Win32
+ {03B8503F-F40D-4013-829C-71B304537D90}.Release|ARM.ActiveCfg = Release|ARM
+ {03B8503F-F40D-4013-829C-71B304537D90}.Release|ARM.Build.0 = Release|ARM
+ {03B8503F-F40D-4013-829C-71B304537D90}.Release|ARM64.ActiveCfg = Release|ARM64
+ {03B8503F-F40D-4013-829C-71B304537D90}.Release|ARM64.Build.0 = Release|ARM64
+ {03B8503F-F40D-4013-829C-71B304537D90}.Release|x64.ActiveCfg = Release|x64
+ {03B8503F-F40D-4013-829C-71B304537D90}.Release|x64.Build.0 = Release|x64
+ {03B8503F-F40D-4013-829C-71B304537D90}.Release|x86.ActiveCfg = Release|Win32
+ {03B8503F-F40D-4013-829C-71B304537D90}.Release|x86.Build.0 = Release|Win32
+ {CA54A654-5E81-44DC-AF3F-CF55EF5B493A}.Debug|ARM.ActiveCfg = Debug|ARM
+ {CA54A654-5E81-44DC-AF3F-CF55EF5B493A}.Debug|ARM.Build.0 = Debug|ARM
+ {CA54A654-5E81-44DC-AF3F-CF55EF5B493A}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {CA54A654-5E81-44DC-AF3F-CF55EF5B493A}.Debug|ARM64.Build.0 = Debug|ARM64
+ {CA54A654-5E81-44DC-AF3F-CF55EF5B493A}.Debug|x64.ActiveCfg = Debug|x64
+ {CA54A654-5E81-44DC-AF3F-CF55EF5B493A}.Debug|x64.Build.0 = Debug|x64
+ {CA54A654-5E81-44DC-AF3F-CF55EF5B493A}.Debug|x86.ActiveCfg = Debug|Win32
+ {CA54A654-5E81-44DC-AF3F-CF55EF5B493A}.Debug|x86.Build.0 = Debug|Win32
+ {CA54A654-5E81-44DC-AF3F-CF55EF5B493A}.Debug|x86.Deploy.0 = Debug|Win32
+ {CA54A654-5E81-44DC-AF3F-CF55EF5B493A}.Release|ARM.ActiveCfg = Release|ARM
+ {CA54A654-5E81-44DC-AF3F-CF55EF5B493A}.Release|ARM.Build.0 = Release|ARM
+ {CA54A654-5E81-44DC-AF3F-CF55EF5B493A}.Release|ARM64.ActiveCfg = Release|ARM64
+ {CA54A654-5E81-44DC-AF3F-CF55EF5B493A}.Release|ARM64.Build.0 = Release|ARM64
+ {CA54A654-5E81-44DC-AF3F-CF55EF5B493A}.Release|x64.ActiveCfg = Release|x64
+ {CA54A654-5E81-44DC-AF3F-CF55EF5B493A}.Release|x64.Build.0 = Release|x64
+ {CA54A654-5E81-44DC-AF3F-CF55EF5B493A}.Release|x86.ActiveCfg = Release|Win32
+ {CA54A654-5E81-44DC-AF3F-CF55EF5B493A}.Release|x86.Build.0 = Release|Win32
+ {CA54A654-5E81-44DC-AF3F-CF55EF5B493A}.Release|x86.Deploy.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {A990658C-CE31-4BCC-976F-0FC6B1AF693D} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}
+ {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}
+ {C38970C0-5FBF-4D69-90D8-CBAC225AE895} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}
+ {F7D32BD0-2749-483E-9A0D-1635EF7E3136} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}
+ {0CC28589-39E4-4288-B162-97B959F8B843} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}
+ {A62D504A-16B8-41D2-9F19-E2E86019E5E4} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}
+ {DA8B35B3-DA00-4B02-BDE6-6A397B3FD46B} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}
+ {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}
+ {2049DBE9-8D13-42C9-AE4B-413AE38FFFD0} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}
+ {84E05BFA-CBAF-4F0D-BFB6-4CE85742A57E} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}
+ {EF074BA1-2D54-4D49-A28E-5E040B47CD2E} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}
+ {F2824844-CE15-4242-9420-308923CD76C3} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}
+ {ADED4FBE-887D-4271-AF24-F0823BCE7961} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {D43FAD39-F619-437D-BB40-04A3982ACB6A}
+ EndGlobalSection
+EndGlobal
diff --git a/example/windows/PDFExample/.gitignore b/example/windows/PDFExample/.gitignore
new file mode 100644
index 00000000..917243bd
--- /dev/null
+++ b/example/windows/PDFExample/.gitignore
@@ -0,0 +1 @@
+/Bundle
diff --git a/example/windows/PDFExample/App.cpp b/example/windows/PDFExample/App.cpp
new file mode 100644
index 00000000..d21b7c72
--- /dev/null
+++ b/example/windows/PDFExample/App.cpp
@@ -0,0 +1,80 @@
+#include "pch.h"
+
+#include "App.h"
+
+#include "AutolinkedNativeModules.g.h"
+#include "ReactPackageProvider.h"
+
+
+using namespace winrt::PDFExample;
+using namespace winrt::PDFExample::implementation;
+using namespace winrt;
+using namespace Windows::UI::Xaml;
+using namespace Windows::UI::Xaml::Controls;
+using namespace Windows::UI::Xaml::Navigation;
+using namespace Windows::ApplicationModel;
+
+///
+/// Initializes the singleton application object. This is the first line of
+/// authored code executed, and as such is the logical equivalent of main() or
+/// WinMain().
+///
+App::App() noexcept
+{
+#if BUNDLE
+ JavaScriptBundleFile(L"index.windows");
+ InstanceSettings().UseWebDebugger(false);
+ InstanceSettings().UseFastRefresh(false);
+#else
+ JavaScriptMainModuleName(L"index");
+ InstanceSettings().UseWebDebugger(true);
+ InstanceSettings().UseFastRefresh(true);
+#endif
+
+#if _DEBUG
+ InstanceSettings().UseDeveloperSupport(true);
+#else
+ InstanceSettings().UseDeveloperSupport(false);
+#endif
+
+ RegisterAutolinkedNativeModulePackages(PackageProviders()); // Includes any autolinked modules
+
+ PackageProviders().Append(make()); // Includes all modules in this project
+ PackageProviders().Append(winrt::progress_view::ReactPackageProvider());
+ InitializeComponent();
+}
+
+///
+/// Invoked when the application is launched normally by the end user. Other entry points
+/// will be used such as when the application is launched to open a specific file.
+///
+/// Details about the launch request and process.
+void App::OnLaunched(activation::LaunchActivatedEventArgs const& e)
+{
+ super::OnLaunched(e);
+
+ Frame rootFrame = Window::Current().Content().as();
+ rootFrame.Navigate(xaml_typename(), box_value(e.Arguments()));
+}
+
+///
+/// Invoked when application execution is being suspended. Application state is saved
+/// without knowing whether the application will be terminated or resumed with the contents
+/// of memory still intact.
+///
+/// The source of the suspend request.
+/// Details about the suspend request.
+void App::OnSuspending([[maybe_unused]] IInspectable const& sender, [[maybe_unused]] SuspendingEventArgs const& e)
+{
+ // Save application state and stop any background activity
+}
+
+///
+/// Invoked when Navigation to a certain page fails
+///
+/// The Frame which failed navigation
+/// Details about the navigation failure
+void App::OnNavigationFailed(IInspectable const&, NavigationFailedEventArgs const& e)
+{
+ throw hresult_error(E_FAIL, hstring(L"Failed to load Page ") + e.SourcePageType().Name);
+}
diff --git a/example/windows/PDFExample/App.h b/example/windows/PDFExample/App.h
new file mode 100644
index 00000000..e94396f5
--- /dev/null
+++ b/example/windows/PDFExample/App.h
@@ -0,0 +1,20 @@
+#pragma once
+
+#include "App.xaml.g.h"
+
+namespace activation = winrt::Windows::ApplicationModel::Activation;
+
+namespace winrt::PDFExample::implementation
+{
+ struct App : AppT
+ {
+ App() noexcept;
+ void OnLaunched(activation::LaunchActivatedEventArgs const&);
+ void OnSuspending(IInspectable const&, Windows::ApplicationModel::SuspendingEventArgs const&);
+ void OnNavigationFailed(IInspectable const&, Windows::UI::Xaml::Navigation::NavigationFailedEventArgs const&);
+ private:
+ using super = AppT;
+ };
+} // namespace winrt::PDFExample::implementation
+
+
diff --git a/example/windows/PDFExample/App.idl b/example/windows/PDFExample/App.idl
new file mode 100644
index 00000000..0c75a56d
--- /dev/null
+++ b/example/windows/PDFExample/App.idl
@@ -0,0 +1,3 @@
+namespace PDFExample
+{
+}
diff --git a/example/windows/PDFExample/App.xaml b/example/windows/PDFExample/App.xaml
new file mode 100644
index 00000000..5117f6f4
--- /dev/null
+++ b/example/windows/PDFExample/App.xaml
@@ -0,0 +1,10 @@
+
+
+
+
+
diff --git a/example/windows/PDFExample/Assets/LockScreenLogo.scale-200.png b/example/windows/PDFExample/Assets/LockScreenLogo.scale-200.png
new file mode 100644
index 00000000..735f57ad
Binary files /dev/null and b/example/windows/PDFExample/Assets/LockScreenLogo.scale-200.png differ
diff --git a/example/windows/PDFExample/Assets/SplashScreen.scale-200.png b/example/windows/PDFExample/Assets/SplashScreen.scale-200.png
new file mode 100644
index 00000000..023e7f1f
Binary files /dev/null and b/example/windows/PDFExample/Assets/SplashScreen.scale-200.png differ
diff --git a/example/windows/PDFExample/Assets/Square150x150Logo.scale-200.png b/example/windows/PDFExample/Assets/Square150x150Logo.scale-200.png
new file mode 100644
index 00000000..af49fec1
Binary files /dev/null and b/example/windows/PDFExample/Assets/Square150x150Logo.scale-200.png differ
diff --git a/example/windows/PDFExample/Assets/Square44x44Logo.scale-200.png b/example/windows/PDFExample/Assets/Square44x44Logo.scale-200.png
new file mode 100644
index 00000000..ce342a2e
Binary files /dev/null and b/example/windows/PDFExample/Assets/Square44x44Logo.scale-200.png differ
diff --git a/example/windows/PDFExample/Assets/Square44x44Logo.targetsize-24_altform-unplated.png b/example/windows/PDFExample/Assets/Square44x44Logo.targetsize-24_altform-unplated.png
new file mode 100644
index 00000000..f6c02ce9
Binary files /dev/null and b/example/windows/PDFExample/Assets/Square44x44Logo.targetsize-24_altform-unplated.png differ
diff --git a/example/windows/PDFExample/Assets/StoreLogo.png b/example/windows/PDFExample/Assets/StoreLogo.png
new file mode 100644
index 00000000..7385b56c
Binary files /dev/null and b/example/windows/PDFExample/Assets/StoreLogo.png differ
diff --git a/example/windows/PDFExample/Assets/Wide310x150Logo.scale-200.png b/example/windows/PDFExample/Assets/Wide310x150Logo.scale-200.png
new file mode 100644
index 00000000..288995b3
Binary files /dev/null and b/example/windows/PDFExample/Assets/Wide310x150Logo.scale-200.png differ
diff --git a/example/windows/PDFExample/AutolinkedNativeModules.g.cpp b/example/windows/PDFExample/AutolinkedNativeModules.g.cpp
new file mode 100644
index 00000000..58eabd79
--- /dev/null
+++ b/example/windows/PDFExample/AutolinkedNativeModules.g.cpp
@@ -0,0 +1,18 @@
+// AutolinkedNativeModules.g.cpp contents generated by "react-native autolink-windows"
+// clang-format off
+#include "pch.h"
+#include "AutolinkedNativeModules.g.h"
+
+// Includes from react-native-pdf
+#include
+
+namespace winrt::Microsoft::ReactNative
+{
+
+void RegisterAutolinkedNativeModulePackages(winrt::Windows::Foundation::Collections::IVector const& packageProviders)
+{
+ // IReactPackageProviders from react-native-pdf
+ packageProviders.Append(winrt::RCTPdf::ReactPackageProvider());
+}
+
+}
diff --git a/example/windows/PDFExample/AutolinkedNativeModules.g.h b/example/windows/PDFExample/AutolinkedNativeModules.g.h
new file mode 100644
index 00000000..1bf5f894
--- /dev/null
+++ b/example/windows/PDFExample/AutolinkedNativeModules.g.h
@@ -0,0 +1,10 @@
+// AutolinkedNativeModules.g.h contents generated by "react-native autolink-windows"
+
+#pragma once
+
+namespace winrt::Microsoft::ReactNative
+{
+
+void RegisterAutolinkedNativeModulePackages(winrt::Windows::Foundation::Collections::IVector const& packageProviders);
+
+}
diff --git a/example/windows/PDFExample/AutolinkedNativeModules.g.targets b/example/windows/PDFExample/AutolinkedNativeModules.g.targets
new file mode 100644
index 00000000..c3cec5b0
--- /dev/null
+++ b/example/windows/PDFExample/AutolinkedNativeModules.g.targets
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+ {03b8503f-f40d-4013-829c-71b304537d90}
+
+
+
diff --git a/example/windows/PDFExample/MainPage.cpp b/example/windows/PDFExample/MainPage.cpp
new file mode 100644
index 00000000..9027fe33
--- /dev/null
+++ b/example/windows/PDFExample/MainPage.cpp
@@ -0,0 +1,24 @@
+#include "pch.h"
+#include "MainPage.h"
+#if __has_include("MainPage.g.cpp")
+#include "MainPage.g.cpp"
+#endif
+
+#include "App.h"
+
+
+
+using namespace winrt;
+using namespace Windows::UI::Xaml;
+
+namespace winrt::PDFExample::implementation
+{
+ MainPage::MainPage()
+ {
+ InitializeComponent();
+ auto app = Application::Current().as();
+ ReactRootView().ReactNativeHost(app->Host());
+ }
+}
+
+
diff --git a/example/windows/PDFExample/MainPage.h b/example/windows/PDFExample/MainPage.h
new file mode 100644
index 00000000..7c1579c9
--- /dev/null
+++ b/example/windows/PDFExample/MainPage.h
@@ -0,0 +1,21 @@
+#pragma once
+#include "MainPage.g.h"
+#include
+
+
+namespace winrt::PDFExample::implementation
+{
+ struct MainPage : MainPageT
+ {
+ MainPage();
+ };
+}
+
+namespace winrt::PDFExample::factory_implementation
+{
+ struct MainPage : MainPageT
+ {
+ };
+}
+
+
diff --git a/example/windows/PDFExample/MainPage.idl b/example/windows/PDFExample/MainPage.idl
new file mode 100644
index 00000000..dd74bbf0
--- /dev/null
+++ b/example/windows/PDFExample/MainPage.idl
@@ -0,0 +1,8 @@
+namespace PDFExample
+{
+ [default_interface]
+ runtimeclass MainPage : Windows.UI.Xaml.Controls.Page
+ {
+ MainPage();
+ }
+}
diff --git a/example/windows/PDFExample/MainPage.xaml b/example/windows/PDFExample/MainPage.xaml
new file mode 100644
index 00000000..37f0b163
--- /dev/null
+++ b/example/windows/PDFExample/MainPage.xaml
@@ -0,0 +1,16 @@
+
+
+
diff --git a/example/windows/PDFExample/PDFExample.vcxproj b/example/windows/PDFExample/PDFExample.vcxproj
new file mode 100644
index 00000000..b0eb7ee5
--- /dev/null
+++ b/example/windows/PDFExample/PDFExample.vcxproj
@@ -0,0 +1,205 @@
+
+
+
+
+ true
+ true
+ true
+ {95f9323c-1039-4b6a-b69e-a9efddfefb54}
+ PDFExample
+ PDFExample
+ en-US
+ 16.0
+ true
+ Windows Store
+ 10.0
+ 10.0.18362.0
+ 10.0.16299.0
+ PDFExample_TemporaryKey.pfx
+ E03C74524183D74C00377AF0154C246C9456C18F
+ password
+
+
+
+ $([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), 'node_modules\react-native-windows\package.json'))\node_modules\react-native-windows\
+
+
+
+ Debug
+ ARM
+
+
+ Debug
+ ARM64
+
+
+ Debug
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ ARM
+
+
+ Release
+ ARM64
+
+
+ Release
+ Win32
+
+
+ Release
+ x64
+
+
+
+ Application
+ Unicode
+
+
+ true
+ true
+
+
+ false
+ true
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Use
+ pch.h
+ $(IntDir)pch.pch
+ Level4
+ %(AdditionalOptions) /bigobj
+ 4453;28204
+
+
+
+
+ _DEBUG;%(PreprocessorDefinitions)
+
+
+
+
+ NDEBUG;%(PreprocessorDefinitions)
+
+
+
+
+ MainPage.xaml
+ Code
+
+
+
+
+
+ App.xaml
+
+
+
+
+ Designer
+
+
+
+
+ Designer
+
+
+
+
+
+
+
+
+
+
+
+
+
+ MainPage.xaml
+ Code
+
+
+
+
+ Create
+
+
+ App.xaml
+
+
+
+
+
+ App.xaml
+
+
+ MainPage.xaml
+ Code
+
+
+
+
+ true
+
+
+
+
+ false
+
+
+
+
+ Designer
+
+
+
+
+ {ca54a654-5e81-44dc-af3f-cf55ef5b493a}
+
+
+
+
+
+
+
+
+ This project references targets in your node_modules\react-native-windows folder. The missing file is {0}.
+
+
+
+
+
+
+
+
+
+
+ This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
+
+
+
+
+
+
\ No newline at end of file
diff --git a/example/windows/PDFExample/PDFExample.vcxproj.filters b/example/windows/PDFExample/PDFExample.vcxproj.filters
new file mode 100644
index 00000000..0f299790
--- /dev/null
+++ b/example/windows/PDFExample/PDFExample.vcxproj.filters
@@ -0,0 +1,64 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+
+
+
+
+
+ {e48dc53e-40b1-40cb-970a-f89935452892}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/example/windows/PDFExample/PDFExample_TemporaryKey.pfx b/example/windows/PDFExample/PDFExample_TemporaryKey.pfx
new file mode 100644
index 00000000..2fb7facd
Binary files /dev/null and b/example/windows/PDFExample/PDFExample_TemporaryKey.pfx differ
diff --git a/example/windows/PDFExample/Package.appxmanifest b/example/windows/PDFExample/Package.appxmanifest
new file mode 100644
index 00000000..65067f9a
--- /dev/null
+++ b/example/windows/PDFExample/Package.appxmanifest
@@ -0,0 +1,52 @@
+
+
+
+
+
+
+
+
+
+ PDFExample
+ ja
+ Assets\StoreLogo.png
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/example/windows/PDFExample/PropertySheet.props b/example/windows/PDFExample/PropertySheet.props
new file mode 100644
index 00000000..5942ba39
--- /dev/null
+++ b/example/windows/PDFExample/PropertySheet.props
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/example/windows/PDFExample/ReactPackageProvider.cpp b/example/windows/PDFExample/ReactPackageProvider.cpp
new file mode 100644
index 00000000..9a3b3bb0
--- /dev/null
+++ b/example/windows/PDFExample/ReactPackageProvider.cpp
@@ -0,0 +1,18 @@
+#include "pch.h"
+#include "ReactPackageProvider.h"
+#include "NativeModules.h"
+
+
+using namespace winrt::Microsoft::ReactNative;
+
+namespace winrt::PDFExample::implementation
+{
+
+void ReactPackageProvider::CreatePackage(IReactPackageBuilder const &packageBuilder) noexcept
+{
+ AddAttributedModules(packageBuilder);
+}
+
+} // namespace winrt::PDFExample::implementation
+
+
diff --git a/example/windows/PDFExample/ReactPackageProvider.h b/example/windows/PDFExample/ReactPackageProvider.h
new file mode 100644
index 00000000..1be3c878
--- /dev/null
+++ b/example/windows/PDFExample/ReactPackageProvider.h
@@ -0,0 +1,15 @@
+#pragma once
+
+#include "winrt/Microsoft.ReactNative.h"
+
+
+namespace winrt::PDFExample::implementation
+{
+ struct ReactPackageProvider : winrt::implements
+ {
+ public: // IReactPackageProvider
+ void CreatePackage(winrt::Microsoft::ReactNative::IReactPackageBuilder const &packageBuilder) noexcept;
+ };
+} // namespace winrt::PDFExample::implementation
+
+
diff --git a/example/windows/PDFExample/packages.config b/example/windows/PDFExample/packages.config
new file mode 100644
index 00000000..7ad3ffb8
--- /dev/null
+++ b/example/windows/PDFExample/packages.config
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/example/windows/PDFExample/pch.cpp b/example/windows/PDFExample/pch.cpp
new file mode 100644
index 00000000..bcb5590b
--- /dev/null
+++ b/example/windows/PDFExample/pch.cpp
@@ -0,0 +1 @@
+#include "pch.h"
diff --git a/example/windows/PDFExample/pch.h b/example/windows/PDFExample/pch.h
new file mode 100644
index 00000000..e3d762be
--- /dev/null
+++ b/example/windows/PDFExample/pch.h
@@ -0,0 +1,29 @@
+#pragma once
+
+#define NOMINMAX
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+#include "winrt/RCTPdf.h"
+#include "winrt/progress_view.h"
diff --git a/index.js b/index.js
index edd49e82..740c3e72 100644
--- a/index.js
+++ b/index.js
@@ -21,7 +21,16 @@ import {
import { ProgressBar } from '@react-native-community/progress-bar-android'
import { ProgressView } from '@react-native-community/progress-view'
-import RNFetchBlob from 'rn-fetch-blob';
+let RNFetchBlob = {
+ fs : {
+ dirs: {
+ CacheDir: ''
+ }
+ }
+};
+if (Platform.OS !== 'windows') {
+ RNFetchBlob = require('rn-fetch-blob');
+}
const SHA1 = require('crypto-js/sha1');
import PdfView from './PdfView';
@@ -166,12 +175,10 @@ export default class Pdf extends Component {
const source = Image.resolveAssetSource(newSource) || {};
let uri = source.uri || '';
-
// first set to initial state
if (this._mounted) {
this.setState({isDownloaded: false, path: '', progress: 0});
}
-
const cacheFile = RNFetchBlob.fs.dirs.CacheDir + '/' + SHA1(uri) + '.pdf';
if (source.cache) {
@@ -392,7 +399,7 @@ export default class Pdf extends Component {
};
render() {
- if (Platform.OS === "android" || Platform.OS === "ios") {
+ if (Platform.OS === "android" || Platform.OS === "ios" || Platform.OS === "windows") {
return (
{!this.state.isDownloaded?
@@ -415,7 +422,7 @@ export default class Pdf extends Component {
{...this.props.activityIndicatorProps}
/>}
):(
- Platform.OS === "android"?(
+ Platform.OS === "android" || Platform.OS === "windows"?(
(this._root = component)}
{...this.props}
@@ -463,6 +470,10 @@ if (Platform.OS === "android") {
var PdfCustom = requireNativeComponent('RCTPdfView', Pdf, {
nativeOnly: {path: true, onChange: true},
})
+} else if (Platform.OS === "windows") {
+ var PdfCustom = requireNativeComponent('RCTPdf', Pdf, {
+ nativeOnly: {path: true, onChange: true},
+ })
}
diff --git a/windows/RCTPdf/PropertySheet.props b/windows/RCTPdf/PropertySheet.props
new file mode 100644
index 00000000..5942ba39
--- /dev/null
+++ b/windows/RCTPdf/PropertySheet.props
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/windows/RCTPdf/RCTPdf.def b/windows/RCTPdf/RCTPdf.def
new file mode 100644
index 00000000..24e7c123
--- /dev/null
+++ b/windows/RCTPdf/RCTPdf.def
@@ -0,0 +1,3 @@
+EXPORTS
+DllCanUnloadNow = WINRT_CanUnloadNow PRIVATE
+DllGetActivationFactory = WINRT_GetActivationFactory PRIVATE
diff --git a/windows/RCTPdf/RCTPdf.vcxproj b/windows/RCTPdf/RCTPdf.vcxproj
new file mode 100644
index 00000000..16839929
--- /dev/null
+++ b/windows/RCTPdf/RCTPdf.vcxproj
@@ -0,0 +1,180 @@
+
+
+
+
+ true
+ true
+ true
+ {03b8503f-f40d-4013-829c-71b304537d90}
+ RCTPdf
+ RCTPdf
+ en-US
+ 16.0
+ true
+ Windows Store
+ 10.0
+ 10.0.18362.0
+ 10.0.16299.0
+
+
+
+ $([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), 'node_modules\react-native-windows\package.json'))\node_modules\react-native-windows\
+
+
+
+ Debug
+ ARM
+
+
+ Debug
+ ARM64
+
+
+ Debug
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ ARM
+
+
+ Release
+ ARM64
+
+
+ Release
+ Win32
+
+
+ Release
+ x64
+
+
+
+ DynamicLibrary
+ Unicode
+ false
+
+
+ true
+ true
+
+
+ false
+ true
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Use
+ pch.h
+ $(IntDir)pch.pch
+ Level4
+ %(AdditionalOptions) /bigobj
+
+ /DWINRT_NO_MAKE_DETECTION %(AdditionalOptions)
+ 28204
+ _WINRT_DLL;%(PreprocessorDefinitions)
+ $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories)
+
+
+ Console
+ true
+ RCTPdf.def
+
+
+
+
+ _DEBUG;%(PreprocessorDefinitions)
+ ProgramDatabase
+
+
+
+
+ NDEBUG;%(PreprocessorDefinitions)
+
+
+
+
+ RCTPdfControl.xaml
+ Code
+
+
+
+
+ ReactPackageProvider.idl
+
+
+
+
+ RCTPdfControl.xaml
+ Code
+
+
+ Create
+
+
+
+ ReactPackageProvider.idl
+
+
+
+
+
+ RCTPdfControl.xaml
+ Code
+
+
+
+
+
+
+
+
+
+
+
+
+ Designer
+
+
+
+
+
+
+
+
+ This project references targets in your node_modules\react-native-windows folder. The missing file is {0}.
+
+
+
+
+
+
+
+
+
+ This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
+
+
+
+
+
\ No newline at end of file
diff --git a/windows/RCTPdf/RCTPdf.vcxproj.filters b/windows/RCTPdf/RCTPdf.vcxproj.filters
new file mode 100644
index 00000000..bd7347df
--- /dev/null
+++ b/windows/RCTPdf/RCTPdf.vcxproj.filters
@@ -0,0 +1,38 @@
+
+
+
+
+ accd3aa8-1ba0-4223-9bbe-0c431709210b
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tga;tiff;tif;png;wav;mfcribbon-ms
+
+
+ {926ab91d-31b5-48c3-b9a4-e681349f27f0}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/windows/RCTPdf/RCTPdfControl.cpp b/windows/RCTPdf/RCTPdfControl.cpp
new file mode 100644
index 00000000..e3a00d09
--- /dev/null
+++ b/windows/RCTPdf/RCTPdfControl.cpp
@@ -0,0 +1,662 @@
+#include "pch.h"
+#include "RCTPdfControl.h"
+#if __has_include("RCTPdfControl.g.cpp")
+#include "RCTPdfControl.g.cpp"
+#endif
+
+using namespace winrt;
+using namespace Windows::UI::Xaml;
+using namespace Microsoft::ReactNative;
+using namespace Windows::Data::Json;
+using namespace Windows::Data::Pdf;
+using namespace Windows::Foundation;
+using namespace Windows::Storage;
+using namespace Windows::Storage::Streams;
+using namespace Windows::Storage::Pickers;
+using namespace Windows::UI;
+using namespace Windows::UI::Core;
+using namespace Windows::UI::Popups;
+using namespace Windows::UI::Xaml;
+using namespace Windows::UI::Xaml::Controls;
+using namespace Windows::UI::Xaml::Input;
+using namespace Windows::UI::Xaml::Media;
+using namespace Windows::UI::Xaml::Media::Imaging;
+
+namespace winrt::RCTPdf::implementation
+{
+ PDFPageInfo::PDFPageInfo(winrt::Windows::UI::Xaml::Controls::Image image, winrt::Windows::Data::Pdf::PdfPage page, double imageScale, double renderScale) :
+ image(image), page(page), imageScale(imageScale), renderScale(renderScale), scaledTopOffset(0), scaledLeftOffset(0) {
+ auto dims = page.Size();
+ height = (unsigned)dims.Height;
+ width = (unsigned)dims.Width;
+ scaledHeight = (unsigned)(height * imageScale);
+ scaledWidth = (unsigned)(width * imageScale);
+ }
+ PDFPageInfo::PDFPageInfo(const PDFPageInfo& rhs) :
+ height(rhs.height), width(rhs.width), scaledHeight(rhs.scaledHeight), scaledWidth(rhs.scaledWidth),
+ scaledTopOffset(rhs.scaledTopOffset), scaledLeftOffset(rhs.scaledTopOffset), imageScale(rhs.imageScale),
+ renderScale((double)rhs.renderScale), image(rhs.image), page(rhs.page)
+ { }
+ PDFPageInfo::PDFPageInfo(PDFPageInfo&& rhs) :
+ height(rhs.height), width(rhs.width), scaledHeight(rhs.scaledHeight), scaledWidth(rhs.scaledWidth),
+ scaledTopOffset(rhs.scaledTopOffset), scaledLeftOffset(rhs.scaledTopOffset), imageScale(rhs.imageScale),
+ renderScale((double)rhs.renderScale), image(std::move(rhs.image)), page(std::move(rhs.page))
+ { }
+ unsigned PDFPageInfo::pageVisiblePixels(bool horizontal, double viewportStart, double viewportEnd) const {
+ if (viewportEnd < viewportStart)
+ std::swap(viewportStart, viewportEnd);
+ auto pageStart = horizontal ? scaledLeftOffset : scaledTopOffset;
+ auto pageSize = PDFPageInfo::pageSize(horizontal);
+ auto pageEnd = pageStart + pageSize;
+ auto uViewportStart = (unsigned)viewportStart;
+ auto uViewportEnd = (unsigned)viewportEnd;
+ if (pageStart >= uViewportStart && pageStart <= uViewportEnd) { // we see the top edge
+ return (std::min)(pageEnd, uViewportEnd) - pageStart;
+ }
+ if (pageEnd >= uViewportStart && pageEnd <= uViewportEnd) { // we see the bottom edge
+ return pageEnd - (std::max)(pageStart, uViewportStart);
+ }
+ if (pageStart <= uViewportStart && pageEnd >= uViewportEnd) {// we see the entire page
+ return uViewportEnd - uViewportStart;
+ }
+ return 0;
+ }
+ unsigned PDFPageInfo::pageSize(bool horizontal) const {
+ return horizontal ? scaledWidth : scaledHeight;
+ }
+ bool PDFPageInfo::needsRender() const {
+ double currentRenderScale = renderScale;
+ return currentRenderScale < imageScale || currentRenderScale > imageScale * m_downscaleTreshold;
+ }
+ winrt::IAsyncAction PDFPageInfo::render() {
+ return render(imageScale);
+ }
+ winrt::IAsyncAction PDFPageInfo::render(double useScale) {
+ double currentRenderScale;
+ while (true) {
+ currentRenderScale = renderScale;
+ if (!(currentRenderScale < imageScale || currentRenderScale > imageScale * m_downscaleTreshold))
+ co_return;
+ if (renderScale.compare_exchange_weak(currentRenderScale, useScale))
+ break;
+ if (renderScale > useScale)
+ co_return;
+ }
+ PdfPageRenderOptions renderOptions;
+ auto dims = page.Size();
+ renderOptions.DestinationHeight(static_cast(dims.Height * useScale));
+ renderOptions.DestinationWidth(static_cast(dims.Width * useScale));
+ InMemoryRandomAccessStream stream;
+ co_await page.RenderToStreamAsync(stream, renderOptions);
+ BitmapImage bitmap;
+ co_await bitmap.SetSourceAsync(stream);
+ if (renderScale == useScale)
+ image.Source(bitmap);
+ }
+
+ RCTPdfControl::RCTPdfControl(IReactContext const& reactContext) : m_reactContext(reactContext) {
+ InitializeComponent();
+ }
+
+ winrt::Windows::Foundation::Collections::IMapView RCTPdfControl::NativeProps() noexcept {
+ auto nativeProps = winrt::single_threaded_map();
+ nativeProps.Insert(L"path", ViewManagerPropertyType::String);
+ nativeProps.Insert(L"page", ViewManagerPropertyType::Number);
+ nativeProps.Insert(L"scale", ViewManagerPropertyType::Number);
+ nativeProps.Insert(L"minScale", ViewManagerPropertyType::Number);
+ nativeProps.Insert(L"maxScale", ViewManagerPropertyType::Number);
+ nativeProps.Insert(L"horizontal", ViewManagerPropertyType::Boolean);
+ nativeProps.Insert(L"fitWidth", ViewManagerPropertyType::Boolean);
+ nativeProps.Insert(L"fitPolicy", ViewManagerPropertyType::Number);
+ nativeProps.Insert(L"spacing", ViewManagerPropertyType::Number);
+ nativeProps.Insert(L"password", ViewManagerPropertyType::String);
+ nativeProps.Insert(L"background", ViewManagerPropertyType::Color);
+ nativeProps.Insert(L"enablePaging", ViewManagerPropertyType::Boolean);
+ nativeProps.Insert(L"enableRTL", ViewManagerPropertyType::Boolean);
+ nativeProps.Insert(L"singlePage", ViewManagerPropertyType::Boolean);
+
+ return nativeProps.GetView();
+ }
+
+ void RCTPdfControl::UpdateProperties(winrt::Microsoft::ReactNative::IJSValueReader const& propertyMapReader) noexcept {
+ const JSValueObject& propertyMap = JSValue::ReadObjectFrom(propertyMapReader);
+ std::optional pdfURI;
+ std::optional pdfPassword;
+ std::optional setPage;
+ std::optional minScale, maxScale, scale;
+ std::optional horizontal;
+ std::optional fitWidth;
+ std::optional fitPolicy;
+ std::optional spacing;
+ std::optional reverse;
+ std::optional singlePage;
+ std::optional enablePaging;
+ for (auto const& pair : propertyMap) {
+ auto const& propertyName = pair.first;
+ auto const& propertyValue = pair.second;
+ if (propertyName == "path") {
+ pdfURI = propertyValue != nullptr ? propertyValue.AsString() : "";
+ }
+ else if (propertyName == "password") {
+ pdfPassword = propertyValue != nullptr ? propertyValue.AsString() : "";
+ }
+ else if (propertyName == "page" && propertyValue != nullptr) {
+ setPage = propertyValue.AsInt32() - 1;
+ }
+ else if (propertyName == "scale" && propertyValue != nullptr) {
+ scale = propertyValue.AsDouble();
+ }
+ else if (propertyName == "minScale" && propertyValue != nullptr) {
+ minScale = propertyValue.AsDouble();
+ }
+ else if (propertyName == "maxScale" && propertyValue != nullptr) {
+ maxScale = propertyValue.AsDouble();
+ }
+ else if (propertyName == "horizontal" && propertyValue != nullptr) {
+ horizontal = propertyValue.AsBoolean();
+ }
+ else if (propertyName == "enablePaging" && propertyValue != nullptr) {
+ enablePaging = propertyValue.AsBoolean();
+ }
+ else if (propertyName == "fitWidth" && propertyValue != nullptr) {
+ fitWidth = propertyValue.AsBoolean();
+ }
+ else if (propertyName == "fitPolic" && propertyValue != nullptr) {
+ fitPolicy = propertyValue.AsInt32();
+ }
+ else if (propertyName == "spacing" && propertyValue != nullptr) {
+ maxScale = propertyValue.AsInt32();
+ }
+ else if (propertyName == "enableRTL" && propertyValue != nullptr) {
+ reverse = propertyValue.AsBoolean();
+ }
+ else if (propertyName == "singlePage" && propertyValue != nullptr) {
+ singlePage = propertyValue.AsBoolean();
+ }
+ else if (propertyName == "backgroundColor" && propertyValue != nullptr) {
+ auto color = propertyValue.AsInt32();
+ winrt::Windows::UI::Color brushColor;
+ brushColor.A = (color >> 24) & 0xff;
+ brushColor.R = (color >> 16) & 0xff;
+ brushColor.G = (color >> 8) & 0xff;
+ brushColor.B = color & 0xff;
+ PagesContainer().Background(SolidColorBrush(brushColor));
+ }
+ }
+ // If we are loading a new PDF:
+ std::shared_lock lock(m_rwlock);
+ if (pdfURI && *pdfURI != m_pdfURI ||
+ pdfPassword && *pdfPassword != m_pdfPassword ||
+ (reverse && *reverse != m_reverse) ||
+ (enablePaging && *enablePaging != m_enablePaging) ||
+ (singlePage && (m_pages.empty() || *singlePage && m_pages.size() != 1 || !*singlePage && m_pages.size() == 1)) ) {
+ lock.unlock();
+ std::unique_lock write_lock(m_rwlock);
+ m_pdfURI = pdfURI.value_or("");
+ m_pdfPassword = pdfPassword.value_or("");
+ m_currentPage = setPage.value_or(0);
+ m_scale = scale.value_or(m_defualtZoom);
+ m_minScale = minScale.value_or(m_defaultMinZoom);
+ m_maxScale = maxScale.value_or(m_defaultMaxZoom);
+ m_horizontal = horizontal.value_or(false);
+ m_enablePaging = enablePaging.value_or(false);
+ int useFitPolicy = 2;
+ if (fitWidth)
+ useFitPolicy = 0;
+ if (fitPolicy)
+ useFitPolicy = *fitPolicy;
+ m_margins = spacing.value_or(m_defaultMargins);
+ m_reverse = reverse.value_or(false);
+ LoadPDF(std::move(write_lock), useFitPolicy, singlePage.value_or(false));
+ } else {
+ // If we are updating the pdf:
+ m_minScale = minScale.value_or(m_minScale);
+ m_maxScale = maxScale.value_or(m_maxScale);
+ bool needScroll = false;
+ if (horizontal && *horizontal != m_horizontal) {
+ SetOrientation(*horizontal);
+ needScroll = true;
+ }
+ if (setPage) {
+ m_currentPage = *setPage;
+ needScroll = true;
+ }
+ if ((scale && *scale != m_scale) || (spacing && *spacing != m_margins)) {
+ Rescale(scale.value_or(m_scale), spacing.value_or(m_margins), !needScroll);
+ }
+ if (needScroll) {
+ GoToPage(m_currentPage);
+ }
+ }
+ }
+
+ winrt::Microsoft::ReactNative::ConstantProviderDelegate RCTPdfControl::ExportedCustomBubblingEventTypeConstants() noexcept {
+ return [](IJSValueWriter const& constantWriter) {
+ WriteCustomDirectEventTypeConstant(constantWriter, "Change");
+ };
+ }
+ winrt::Microsoft::ReactNative::ConstantProviderDelegate RCTPdfControl::ExportedCustomDirectEventTypeConstants() noexcept {
+ return nullptr;
+ }
+
+ winrt::Windows::Foundation::Collections::IVectorView RCTPdfControl::Commands() noexcept {
+ auto commands = winrt::single_threaded_vector();
+ commands.Append(L"setPage");
+ return commands.GetView();
+ }
+
+ void RCTPdfControl::DispatchCommand(winrt::hstring const& commandId, winrt::Microsoft::ReactNative::IJSValueReader const& commandArgsReader) noexcept {
+ auto commandArgs = JSValue::ReadArrayFrom(commandArgsReader);
+ if (commandId == L"setPage" && commandArgs.size() > 0) {
+ std::shared_lock lock(m_rwlock);
+ auto page = commandArgs[0].AsInt32() - 1;
+ GoToPage(page);
+ }
+ }
+
+ void RCTPdfControl::PagesContainer_PointerWheelChanged(winrt::Windows::Foundation::IInspectable const&, winrt::Windows::UI::Xaml::Input::PointerRoutedEventArgs const& e) {
+ winrt::Windows::System::VirtualKeyModifiers modifiers = e.KeyModifiers();
+ if ((modifiers & winrt::Windows::System::VirtualKeyModifiers::Control) != winrt::Windows::System::VirtualKeyModifiers::Control)
+ return;
+ double delta = (e.GetCurrentPoint(*this).Properties().MouseWheelDelta() / WHEEL_DELTA);
+ std::shared_lock lock(m_rwlock);
+ auto newScale = (std::max)((std::min)(m_scale * pow(m_zoomMultiplier, delta), m_maxScale), m_minScale);
+ Rescale(newScale, m_margins, true);
+ e.Handled(true);
+ }
+
+ void RCTPdfControl::Pages_SizeChanged(winrt::Windows::Foundation::IInspectable const&, winrt::Windows::UI::Xaml::SizeChangedEventArgs const&) {
+ if (m_targetHorizontalOffset || m_targetVerticalOffset) {
+ auto container = PagesContainer();
+ PagesContainer().ChangeView(m_targetHorizontalOffset.value_or(container.HorizontalOffset()),
+ m_targetVerticalOffset.value_or(container.VerticalOffset()),
+ nullptr,
+ true);
+ m_targetHorizontalOffset.reset();
+ m_targetVerticalOffset.reset();
+ }
+ }
+
+ winrt::fire_and_forget RCTPdfControl::PagesContainer_ViewChanged(winrt::Windows::Foundation::IInspectable const&, winrt::Windows::UI::Xaml::Controls::ScrollViewerViewChangedEventArgs const& args)
+ {
+ auto lifetime = get_strong();
+ auto container = PagesContainer();
+ auto currentHorizontalOffset = container.HorizontalOffset();
+ auto currentVerticalOffset = container.VerticalOffset();
+ double offsetStart = m_horizontal ? currentHorizontalOffset : currentVerticalOffset;
+ double viewSize = m_horizontal ? container.ViewportWidth() : container.ViewportHeight();
+ double offsetEnd = offsetStart + viewSize;
+ std::shared_lock lock(m_rwlock, std::defer_lock);
+ if (args.IsIntermediate() || !lock.try_lock() || viewSize == 0 || m_pages.empty())
+ return;
+ // Go through pages until we reach a visible page
+ int page = 0;
+ double visiblePagePixels = 0;
+ for (; page < (int)m_pages.size(); ++page) {
+ visiblePagePixels = m_pages[page].pageVisiblePixels(m_horizontal, offsetStart, offsetEnd);
+ if (visiblePagePixels > 0)
+ break;
+ }
+ if (page == (int)m_pages.size()) {
+ --page;
+ }
+ else {
+ double pagePixels = m_pages[page].pageSize(m_horizontal);
+ // #"page" is the first visible page. Check how much of the view port this page covers...
+ double viewCoveredByPage = visiblePagePixels / viewSize;
+ // ...and how much of the page is visible:
+ double pageVisiblePart = visiblePagePixels / pagePixels;
+ // If:
+ // - less than 50% of the screen is covered by the page
+ // - less than 50% of the page is visible (important if more than one page fits the screen)
+ // - there is a next page
+ // move the indicator to that page:
+ if (viewCoveredByPage < 0.5 && pageVisiblePart < 0.5 && page + 1 < (int)m_pages.size()) {
+ ++page;
+ }
+ }
+ // Render all visible pages - first the current one, then the next visible ones and one
+ // more, then the one before that might be partly visible, then one more before
+ co_await RenderVisiblePages(page);
+ if (page != m_currentPage) {
+ m_currentPage = page;
+ SignalPageChange(m_currentPage + 1, m_pages.size());
+ }
+ }
+
+ void RCTPdfControl::PagesContainer_Tapped(winrt::Windows::Foundation::IInspectable const&, winrt::Windows::UI::Xaml::Input::TappedRoutedEventArgs const& args) {
+ auto position = args.GetPosition(*this);
+ std::shared_lock lock(m_rwlock);
+ int scaledDoubleMargin = (int)(m_scale * m_margins * 2);
+ int page = 0;
+ int xPosition = (int)(position.X + PagesContainer().HorizontalOffset());
+ int yPosition = (int)(position.Y + PagesContainer().VerticalOffset());
+ for (; page < (int)m_pages.size(); ++page) {
+ if (m_horizontal) {
+ if (xPosition >= (int)m_pages[page].scaledLeftOffset &&
+ xPosition <= (int)(m_pages[page].scaledLeftOffset + m_pages[page].scaledWidth + scaledDoubleMargin))
+ break;
+ } else {
+ if (yPosition >= (int)m_pages[page].scaledTopOffset &&
+ yPosition <= (int)(m_pages[page].scaledTopOffset + m_pages[page].scaledHeight + scaledDoubleMargin))
+ break;
+ }
+ }
+ if (page == (int)m_pages.size()) {
+ page = m_currentPage;
+ }
+ SignalPageTapped(page, (int)position.X, (int)position.Y);
+ PagesContainer().Focus(FocusState::Pointer);
+ args.Handled(true);
+ }
+
+
+ void RCTPdfControl::PagesContainer_DoubleTapped(winrt::Windows::Foundation::IInspectable const&, winrt::Windows::UI::Xaml::Input::DoubleTappedRoutedEventArgs const& args)
+ {
+ std::shared_lock lock(m_rwlock);
+ double newScale = (std::min)(m_scale * m_zoomMultiplier, m_maxScale);
+ Rescale(newScale, m_margins, true);
+ PagesContainer().Focus(FocusState::Pointer);
+ args.Handled(true);
+ }
+
+ void RCTPdfControl::ChangeScroll(double targetHorizontalOffset, double targetVerticalOffset) {
+ auto container = PagesContainer();
+ auto maxHorizontalOffset = container.ScrollableWidth();
+ auto maxVerticalOffset = container.ScrollableHeight();
+ // If viewport is bigger than a page, it is possible that target offset is
+ // smaller than max offset. Take that into account:
+ if (targetHorizontalOffset <= maxHorizontalOffset + container.ViewportWidth() &&
+ targetVerticalOffset <= maxVerticalOffset + container.ViewportHeight()) {
+ PagesContainer().ChangeView((std::min)(targetHorizontalOffset, maxHorizontalOffset),
+ (std::min)(targetVerticalOffset, maxVerticalOffset),
+ nullptr, true);
+ }
+ else {
+ m_targetHorizontalOffset = targetHorizontalOffset;
+ m_targetVerticalOffset = targetVerticalOffset;
+ }
+ }
+
+ void RCTPdfControl::UpdatePagesInfoMarginOrScale() {
+ unsigned scaledMargin = (unsigned)(m_scale * m_margins);
+ for (auto& page : m_pages) {
+ page.imageScale = m_scale;
+ page.scaledWidth = (unsigned)(page.width * m_scale);
+ page.scaledHeight = (unsigned)(page.height * m_scale);
+ page.image.Margin(ThicknessHelper::FromUniformLength(scaledMargin));
+ page.image.Width(page.scaledWidth);
+ page.image.Height(page.scaledHeight);
+ }
+ unsigned totalTopOffset = 0;
+ unsigned totalLeftOffset = 0;
+ unsigned doubleScaledMargin = scaledMargin * 2;
+ if (m_reverse) {
+ for (int page = m_pages.size() - 1; page >= 0; --page) {
+ m_pages[page].scaledTopOffset = totalTopOffset;
+ totalTopOffset += m_pages[page].scaledHeight + doubleScaledMargin;
+ m_pages[page].scaledLeftOffset = totalLeftOffset;
+ totalLeftOffset += m_pages[page].scaledWidth + doubleScaledMargin;
+ }
+ }
+ else {
+ for (int page = 0; page < (int)m_pages.size(); ++page) {
+ m_pages[page].scaledTopOffset = totalTopOffset;
+ totalTopOffset += m_pages[page].scaledHeight + doubleScaledMargin;
+ m_pages[page].scaledLeftOffset = totalLeftOffset;
+ totalLeftOffset += m_pages[page].scaledWidth + doubleScaledMargin;
+ }
+ }
+ }
+
+ void RCTPdfControl::GoToPage(int page) {
+ if (page < 0 || page >= (int)m_pages.size()) {
+ return;
+ }
+ if (m_enablePaging) {
+ [&](int page) -> winrt::fire_and_forget {
+ auto lifetime = get_strong();
+ co_await m_pages[page].render();
+ }(page);
+ Pages().Items().ReplaceAll({ &m_pages[page].image, &m_pages[page].image + 1 });
+ } else {
+ auto neededOffset = m_horizontal ? m_pages[page].scaledLeftOffset : m_pages[page].scaledTopOffset;
+ double horizontalOffset = m_horizontal ? neededOffset : PagesContainer().HorizontalOffset();
+ double verticalOffset = m_horizontal ? PagesContainer().VerticalOffset() : neededOffset;
+ ChangeScroll(horizontalOffset, verticalOffset);
+ }
+ SignalPageChange(page + 1, m_pages.size());
+ }
+
+ winrt::fire_and_forget RCTPdfControl::LoadPDF(std::unique_lock lock, int fitPolicy, bool singlePage) {
+ auto lifetime = get_strong();
+ auto pdfURI = m_pdfURI;
+ auto uri = Uri(winrt::to_hstring(pdfURI));
+ auto scheme = uri.SchemeName();
+ if (scheme == L"file") {
+ // backslashes only on Windows
+ std::replace(begin(pdfURI), end(pdfURI), '/', '\\');
+ }
+ PdfDocument document = nullptr;
+ try {
+ auto file = scheme == L"file"
+ ? co_await StorageFile::GetFileFromPathAsync(winrt::to_hstring(pdfURI))
+ : co_await StorageFile::GetFileFromApplicationUriAsync(uri);
+ document = co_await PdfDocument::LoadFromFileAsync(file, winrt::to_hstring(m_pdfPassword));
+ }
+ catch (winrt::hresult_error const& ex) {
+ switch (ex.to_abi()) {
+ case __HRESULT_FROM_WIN32(ERROR_WRONG_PASSWORD):
+ SignalError("Password required or incorrect password.");
+ co_return;
+ case E_FAIL:
+ SignalError("Document is not a valid PDF.");
+ co_return;
+ default:
+ SignalError(winrt::to_string(ex.message()));
+ co_return;
+ }
+ }
+ if (!document) {
+ SignalError("Could not load PDF.");
+ co_return;
+ }
+ auto items = Pages().Items();
+ items.Clear();
+ m_pages.clear();
+ SetOrientation(m_horizontal);
+ if (document.PageCount() == 0) {
+ if (fitPolicy != -1)
+ m_scale = 1;
+ }
+ else {
+ auto firstPageSize = document.GetPage(0).Size();
+ auto viewWidth = PagesContainer().ViewportWidth();
+ auto viewHeight = PagesContainer().ViewportHeight();
+ switch (fitPolicy) {
+ case 0:
+ m_scale = viewWidth / (firstPageSize.Width + 2 * (double)m_margins);
+ break;
+ case 1:
+ m_scale = viewHeight / (firstPageSize.Height + 2 * (double)m_margins);
+ break;
+ case 2:
+ m_scale = (std::min)(viewWidth / (firstPageSize.Width + 2 * (double)m_margins), viewHeight / (firstPageSize.Height + 2 * (double)m_margins));
+ break;
+ default:
+ break;
+ }
+ }
+ unsigned pagesCount = document.PageCount();
+ if (singlePage && pagesCount > 0)
+ pagesCount = 1;
+ for (unsigned pageIdx = 0; pageIdx < pagesCount; ++pageIdx) {
+ auto page = document.GetPage(pageIdx);
+ auto dims = page.Size();
+ Image pageImage;
+ pageImage.HorizontalAlignment(HorizontalAlignment::Center);
+ pageImage.AllowFocusOnInteraction(false);
+ m_pages.emplace_back(pageImage, page, m_scale, 0);
+ }
+ if (m_enablePaging) {
+ items.Append(m_pages[m_currentPage].image);
+ } else {
+ if (m_reverse) {
+ for (int page = m_pages.size() - 1; page >= 0; --page)
+ items.Append(m_pages[page].image);
+ }
+ else {
+ for (int page = 0; page < (int)m_pages.size(); ++page)
+ items.Append(m_pages[page].image);
+ }
+ }
+ UpdatePagesInfoMarginOrScale();
+ lock.unlock();
+ std::shared_lock shared_lock(m_rwlock);
+ if (m_currentPage < 0)
+ m_currentPage = 0;
+ if (m_currentPage < (int)m_pages.size()) {
+ co_await m_pages[m_currentPage].render();
+ GoToPage(m_currentPage);
+ }
+ if (m_pages.empty()) {
+ SignalLoadComplete(0, 0, 0);
+ }
+ else {
+ SignalLoadComplete(m_pages.size(), m_pages.front().width, m_pages.front().height);
+ }
+ // Render low-res preview of the pages
+ double useScale = (std::min)(m_scale, m_previewZoom);
+ for (unsigned page = 0; page < m_pages.size(); ++page) {
+ co_await m_pages[page].render(useScale);
+ }
+ }
+
+ void RCTPdfControl::Rescale(double newScale, double newMargin, bool goToNewPosition) {
+ if (newScale != m_scale || newMargin != m_margins) {
+ double rescale = newScale / m_scale;
+ double targetHorizontalOffset = PagesContainer().HorizontalOffset() * rescale;
+ double targetVerticalOffset = PagesContainer().VerticalOffset() * rescale;
+ if (newMargin != m_margins) {
+ if (m_horizontal) {
+ targetVerticalOffset += (double)m_currentPage * 2 * (newMargin - m_margins) * rescale;
+ }
+ else {
+ targetHorizontalOffset += (double)m_currentPage * 2 * (newMargin - m_margins) * rescale;
+ }
+ }
+ m_scale = newScale;
+ m_margins = (int)newMargin;
+ UpdatePagesInfoMarginOrScale();
+ if (goToNewPosition) {
+ ChangeScroll(targetHorizontalOffset, targetVerticalOffset);
+ }
+ SignalScaleChanged(m_scale);
+ }
+ }
+
+ void RCTPdfControl::SetOrientation(bool horizontal) {
+ m_horizontal = horizontal;
+ FindName(winrt::to_hstring("OrientationSelector")).try_as().Orientation(m_horizontal ? Orientation::Horizontal : Orientation::Vertical);
+ }
+
+ winrt::IAsyncAction RCTPdfControl::RenderVisiblePages(int page) {
+ auto lifetime = get_strong();
+ auto container = PagesContainer();
+ auto currentHorizontalOffset = container.HorizontalOffset();
+ auto currentVerticalOffset = container.VerticalOffset();
+ double offsetStart = m_horizontal ? currentHorizontalOffset : currentVerticalOffset;
+ double viewSize = m_horizontal ? container.ViewportWidth() : container.ViewportHeight();
+ double offsetEnd = offsetStart + viewSize;
+ if (m_pages[page].needsRender()) {
+ co_await m_pages[page].render();
+ }
+ auto pageToRender = page + 1;
+ while (pageToRender < (int)m_pages.size() &&
+ m_pages[pageToRender].pageVisiblePixels(m_horizontal, offsetStart, offsetEnd) > 0) {
+ if (m_pages[pageToRender].needsRender()) {
+ co_await m_pages[pageToRender].render();
+ }
+ ++pageToRender;
+ }
+ if (pageToRender < (int)m_pages.size() && m_pages[pageToRender].needsRender()) {
+ co_await m_pages[pageToRender].render();
+ }
+ if (page >= 1 && m_pages[page - 1].needsRender()) {
+ co_await m_pages[page - 1].render();
+ }
+ if (page >= 2 && m_pages[page - 2].needsRender()) {
+ co_await m_pages[page - 2].render();
+ }
+ }
+
+ void RCTPdfControl::SignalError(const std::string& error) {
+ m_reactContext.DispatchEvent(
+ *this,
+ L"topChange",
+ [&](winrt::Microsoft::ReactNative::IJSValueWriter const& eventDataWriter) noexcept {
+ eventDataWriter.WriteObjectBegin();
+ {
+ WriteProperty(eventDataWriter, L"message", winrt::to_hstring("error|" + error));
+ }
+ eventDataWriter.WriteObjectEnd();
+ });
+ }
+ void RCTPdfControl::SignalLoadComplete(int totalPages, int width, int height) {
+ auto message = "loadComplete|" +
+ std::to_string(totalPages) + "|" +
+ std::to_string(width) + "|" +
+ std::to_string(height) + "|";
+ m_reactContext.DispatchEvent(
+ *this,
+ L"topChange",
+ [&](winrt::Microsoft::ReactNative::IJSValueWriter const& eventDataWriter) noexcept {
+ eventDataWriter.WriteObjectBegin();
+ {
+ WriteProperty(eventDataWriter, L"message", winrt::to_hstring(message));
+ }
+ eventDataWriter.WriteObjectEnd();
+ });
+ }
+ void RCTPdfControl::SignalPageChange(int page, int totalPages) {
+ auto message = "pageChanged|" + std::to_string(page) + "|" + std::to_string(totalPages);
+ m_reactContext.DispatchEvent(
+ *this,
+ L"topChange",
+ [&](winrt::Microsoft::ReactNative::IJSValueWriter const& eventDataWriter) noexcept {
+ eventDataWriter.WriteObjectBegin();
+ {
+ WriteProperty(eventDataWriter, L"message", winrt::to_hstring(message));
+ }
+ eventDataWriter.WriteObjectEnd();
+ });
+ }
+ void RCTPdfControl::SignalScaleChanged(double scale) {
+ m_reactContext.DispatchEvent(
+ *this,
+ L"topChange",
+ [&](winrt::Microsoft::ReactNative::IJSValueWriter const& eventDataWriter) noexcept {
+ eventDataWriter.WriteObjectBegin();
+ {
+ WriteProperty(eventDataWriter, L"message", winrt::to_hstring("scale|" + std::to_string(scale)));
+ }
+ eventDataWriter.WriteObjectEnd();
+ });
+ }
+ void RCTPdfControl::SignalPageTapped(int page, int x, int y) {
+ const std::string message = "pageSingleTap|" +
+ std::to_string(page + 1) + "|" +
+ std::to_string(x) + "|" +
+ std::to_string(y);
+ m_reactContext.DispatchEvent(
+ *this,
+ L"topChange",
+ [&](winrt::Microsoft::ReactNative::IJSValueWriter const& eventDataWriter) noexcept {
+ eventDataWriter.WriteObjectBegin();
+ {
+ WriteProperty(eventDataWriter, L"message", winrt::to_hstring(message));
+ }
+ eventDataWriter.WriteObjectEnd();
+ });
+ }
+}
diff --git a/windows/RCTPdf/RCTPdfControl.h b/windows/RCTPdf/RCTPdfControl.h
new file mode 100644
index 00000000..9a135ec1
--- /dev/null
+++ b/windows/RCTPdf/RCTPdfControl.h
@@ -0,0 +1,119 @@
+#pragma once
+
+#include
+#include "winrt/Windows.UI.Xaml.h"
+#include "winrt/Windows.UI.Xaml.Markup.h"
+#include "winrt/Windows.UI.Xaml.Interop.h"
+#include "winrt/Windows.UI.Xaml.Controls.Primitives.h"
+#include "winrt/Microsoft.ReactNative.h"
+#include "NativeModules.h"
+#include "RCTPdfControl.g.h"
+
+namespace winrt::RCTPdf::implementation
+{
+ struct PDFPageInfo {
+ PDFPageInfo(winrt::Windows::UI::Xaml::Controls::Image image, winrt::Windows::Data::Pdf::PdfPage page, double imageScale, double renderScale);
+ PDFPageInfo(const PDFPageInfo&);
+ PDFPageInfo(PDFPageInfo&&);
+ unsigned pageVisiblePixels(bool horizontal, double viewportStart, double viewportEnd) const;
+ unsigned pageSize(bool horizontal) const;
+ bool needsRender() const;
+ winrt::IAsyncAction render();
+ winrt::IAsyncAction render(double useScale);
+ unsigned height, width;
+ unsigned scaledHeight, scaledWidth;
+ unsigned scaledTopOffset, scaledLeftOffset;
+ double imageScale; // scale at which the image is displayed
+ // Multiple tasks can update the image, use the render scale as the sync point
+ std::atomic renderScale; // scale at which the image is rendered
+ winrt::Windows::UI::Xaml::Controls::Image image;
+ winrt::Windows::Data::Pdf::PdfPage page;
+
+ // If zooming-out at what point we rerender the image with smaller scale?
+ // E.g. value of 2 means if the image is currently rendered at scale 1.0
+ // we will rerender it when the scale is smaller than 0.5
+ static constexpr double m_downscaleTreshold = 2;
+ };
+
+ struct RCTPdfControl : RCTPdfControlT
+ {
+ public:
+ RCTPdfControl(Microsoft::ReactNative::IReactContext const& reactContext);
+
+ static winrt::Windows::Foundation::Collections::IMapView NativeProps() noexcept;
+ void UpdateProperties(winrt::Microsoft::ReactNative::IJSValueReader const& propertyMapReader) noexcept;
+
+ static winrt::Microsoft::ReactNative::ConstantProviderDelegate ExportedCustomBubblingEventTypeConstants() noexcept;
+ static winrt::Microsoft::ReactNative::ConstantProviderDelegate ExportedCustomDirectEventTypeConstants() noexcept;
+
+ static winrt::Windows::Foundation::Collections::IVectorView Commands() noexcept;
+ void DispatchCommand(winrt::hstring const& commandId, winrt::Microsoft::ReactNative::IJSValueReader const& commandArgsReader) noexcept;
+
+ void PagesContainer_PointerWheelChanged(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::Input::PointerRoutedEventArgs const& e);
+ void Pages_SizeChanged(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::SizeChangedEventArgs const& e);
+ winrt::fire_and_forget PagesContainer_ViewChanged(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::Controls::ScrollViewerViewChangedEventArgs const& e);
+ void PagesContainer_Tapped(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::Input::TappedRoutedEventArgs const& e);
+ void PagesContainer_DoubleTapped(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::Input::DoubleTappedRoutedEventArgs const& e);
+ private:
+ Microsoft::ReactNative::IReactContext m_reactContext{ nullptr };
+
+ // Global lock to access the data stuff
+ // the pages are rendered in an async way
+ std::shared_mutex m_rwlock;
+ // URI and password of the PDF
+ std::string m_pdfURI;
+ std::string m_pdfPassword;
+ // Current active page
+ int m_currentPage = 0;
+ // Margins of each page
+ int m_margins = 10;
+ // Scale at which the PDF is displayed
+ double m_scale = 0.2;
+ double m_minScale = 0.1;
+ double m_maxScale = 3.0;
+ // Are we in "horizontal" mode?
+ bool m_horizontal = false;
+ // Render the pages in reverse order
+ bool m_reverse = false;
+ // Is in "enablePaging" mode
+ bool m_enablePaging = false;
+
+ // When we rescale or change the margins, we can jump to the new position in the view
+ // only after the ScrollViewer has updated. We store the target offsets here, and go
+ // to them when the control finishes updating;
+ std::optional m_targetHorizontalOffset;
+ std::optional m_targetVerticalOffset;
+ // It is possible, that the new position is reachable even before the control is updated.
+ // A helper function that either schedules a change in the view or jumps right to
+ // the position
+ void ChangeScroll(double targetHorizontalOffset, double targetVerticalOffset);
+
+ // Pages info
+ std::vector m_pages;
+
+ void UpdatePagesInfoMarginOrScale();
+ winrt::fire_and_forget LoadPDF(std::unique_lock lock, int fitPolicy, bool singlePage);
+ void GoToPage(int page);
+ void Rescale(double newScale, double newMargin, bool goToNewPosition);
+ void SetOrientation(bool horizontal);
+ winrt::IAsyncAction RenderVisiblePages(int page);
+ void SignalError(const std::string& error);
+ void SignalLoadComplete(int totalPages, int width, int height);
+ void SignalPageChange(int page, int totalPages);
+ void SignalScaleChanged(double scale);
+ void SignalPageTapped(int page, int x, int y);
+
+ // Zoom in/out scale multiplier
+ static constexpr double m_zoomMultiplier = 1.2;
+ static constexpr double m_defaultMaxZoom = 3.0;
+ static constexpr double m_defaultMinZoom = 1.0;
+ static constexpr double m_defualtZoom = 1.0;
+ static constexpr int m_defaultMargins = 10;
+ static constexpr double m_previewZoom = 0.5;
+ };
+}
+
+namespace winrt::RCTPdf::factory_implementation {
+ struct RCTPdfControl : RCTPdfControlT {
+ };
+}
diff --git a/windows/RCTPdf/RCTPdfControl.idl b/windows/RCTPdf/RCTPdfControl.idl
new file mode 100644
index 00000000..0d0591d3
--- /dev/null
+++ b/windows/RCTPdf/RCTPdfControl.idl
@@ -0,0 +1,10 @@
+namespace RCTPdf
+{
+ [default_interface]
+ runtimeclass RCTPdfControl : Windows.UI.Xaml.Controls.UserControl
+ {
+ RCTPdfControl(Microsoft.ReactNative.IReactContext context);
+ void UpdateProperties(Microsoft.ReactNative.IJSValueReader reader);
+ void DispatchCommand(String commandId, Microsoft.ReactNative.IJSValueReader commandArgsReader);
+ }
+}
diff --git a/windows/RCTPdf/RCTPdfControl.xaml b/windows/RCTPdf/RCTPdfControl.xaml
new file mode 100644
index 00000000..b5466138
--- /dev/null
+++ b/windows/RCTPdf/RCTPdfControl.xaml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/windows/RCTPdf/RCTPdfViewManager.cpp b/windows/RCTPdf/RCTPdfViewManager.cpp
new file mode 100644
index 00000000..b1d1386a
--- /dev/null
+++ b/windows/RCTPdf/RCTPdfViewManager.cpp
@@ -0,0 +1,69 @@
+#include "pch.h"
+#include "NativeModules.h"
+#include "JSValueXaml.h"
+#include "RCTPdfViewManager.h"
+#include "RCTPdfControl.h"
+
+namespace winrt {
+ using namespace Microsoft::ReactNative;
+ using namespace Windows::Foundation;
+ using namespace Windows::Foundation::Collections;
+ using namespace Windows::UI;
+ using namespace Windows::UI::Xaml;
+ using namespace Windows::UI::Xaml::Controls;
+}
+
+namespace winrt::RCTPdf::implementation {
+ // IViewManager
+ winrt::hstring RCTPdfViewManager::Name() noexcept {
+ return L"RCTPdf";
+ }
+
+ winrt::FrameworkElement RCTPdfViewManager::CreateView() noexcept {
+ return winrt::RCTPdf::RCTPdfControl(m_reactContext);
+ }
+
+ // IViewManagerWithReactContext
+ winrt::IReactContext RCTPdfViewManager::ReactContext() noexcept {
+ return m_reactContext;
+ }
+
+ void RCTPdfViewManager::ReactContext(IReactContext reactContext) noexcept {
+ m_reactContext = reactContext;
+ }
+
+ // IViewManagerWithNativeProperties
+ IMapView RCTPdfViewManager::NativeProps() noexcept {
+ return winrt::RCTPdf::implementation::RCTPdfControl::NativeProps();
+ }
+
+ void RCTPdfViewManager::UpdateProperties(
+ FrameworkElement const& view,
+ IJSValueReader const& propertyMapReader) noexcept {
+ if (auto module = view.try_as()) {
+ module.UpdateProperties(propertyMapReader);
+ }
+ }
+ // IViewManagerWithExportedEventTypeConstants
+ ConstantProviderDelegate RCTPdfViewManager::ExportedCustomBubblingEventTypeConstants() noexcept {
+ return winrt::RCTPdf::implementation::RCTPdfControl::ExportedCustomBubblingEventTypeConstants();
+ }
+
+ ConstantProviderDelegate RCTPdfViewManager::ExportedCustomDirectEventTypeConstants() noexcept {
+ return winrt::RCTPdf::implementation::RCTPdfControl::ExportedCustomDirectEventTypeConstants();
+ }
+
+ // IViewManagerWithCommands
+ IVectorView RCTPdfViewManager::Commands() noexcept {
+ return winrt::RCTPdf::implementation::RCTPdfControl::Commands();
+ }
+
+ void RCTPdfViewManager::DispatchCommand(
+ FrameworkElement const& view,
+ winrt::hstring const& commandId,
+ winrt::IJSValueReader const& commandArgsReader) noexcept {
+ if (auto module = view.try_as()) {
+ module.DispatchCommand(commandId, commandArgsReader);
+ }
+ }
+}
diff --git a/windows/RCTPdf/RCTPdfViewManager.h b/windows/RCTPdf/RCTPdfViewManager.h
new file mode 100644
index 00000000..fa2aaee0
--- /dev/null
+++ b/windows/RCTPdf/RCTPdfViewManager.h
@@ -0,0 +1,51 @@
+#pragma once
+#include "winrt/Microsoft.ReactNative.h"
+#include "NativeModules.h"
+
+
+namespace winrt::RCTPdf::implementation {
+
+ class RCTPdfViewManager : public winrt::implements<
+ RCTPdfViewManager,
+ winrt::Microsoft::ReactNative::IViewManager,
+ winrt::Microsoft::ReactNative::IViewManagerWithReactContext,
+ winrt::Microsoft::ReactNative::IViewManagerWithNativeProperties,
+ winrt::Microsoft::ReactNative::IViewManagerWithExportedEventTypeConstants,
+ winrt::Microsoft::ReactNative::IViewManagerWithCommands> {
+ public:
+ RCTPdfViewManager() = default;
+
+ // IViewManager
+ winrt::hstring Name() noexcept;
+ winrt::Windows::UI::Xaml::FrameworkElement CreateView() noexcept;
+
+ // IViewManagerWithReactContext
+ winrt::Microsoft::ReactNative::IReactContext ReactContext() noexcept;
+ void ReactContext(winrt::Microsoft::ReactNative::IReactContext reactContext) noexcept;
+
+ // IViewManagerWithNativeProperties
+ winrt::Windows::Foundation::Collections::
+ IMapView
+ NativeProps() noexcept;
+
+ void UpdateProperties(
+ winrt::Windows::UI::Xaml::FrameworkElement const& view,
+ winrt::Microsoft::ReactNative::IJSValueReader const& propertyMapReader) noexcept;
+
+ // IViewManagerWithExportedEventTypeConstants
+ winrt::Microsoft::ReactNative::ConstantProviderDelegate ExportedCustomBubblingEventTypeConstants() noexcept;
+ winrt::Microsoft::ReactNative::ConstantProviderDelegate ExportedCustomDirectEventTypeConstants() noexcept;
+
+
+ // IViewManagerWithCommands
+ winrt::Windows::Foundation::Collections::IVectorView Commands() noexcept;
+
+ void DispatchCommand(
+ winrt::Windows::UI::Xaml::FrameworkElement const &view,
+ winrt::hstring const &commandId,
+ winrt::Microsoft::ReactNative::IJSValueReader const &commandArgsReader) noexcept;
+
+ private:
+ winrt::Microsoft::ReactNative::IReactContext m_reactContext{ nullptr };
+ };
+}
diff --git a/windows/RCTPdf/ReactPackageProvider.cpp b/windows/RCTPdf/ReactPackageProvider.cpp
new file mode 100644
index 00000000..af554dd0
--- /dev/null
+++ b/windows/RCTPdf/ReactPackageProvider.cpp
@@ -0,0 +1,15 @@
+#include "pch.h"
+#include "ReactPackageProvider.h"
+#if __has_include("ReactPackageProvider.g.cpp")
+# include "ReactPackageProvider.g.cpp"
+#endif
+
+#include "RCTPdfViewManager.h"
+
+using namespace winrt::Microsoft::ReactNative;
+
+namespace winrt::RCTPdf::implementation {
+ void ReactPackageProvider::CreatePackage(IReactPackageBuilder const &packageBuilder) noexcept {
+ packageBuilder.AddViewManager(L"RCTPdfViewManager", []() { return winrt::make(); });
+ }
+}
diff --git a/windows/RCTPdf/ReactPackageProvider.h b/windows/RCTPdf/ReactPackageProvider.h
new file mode 100644
index 00000000..0ce5b9c5
--- /dev/null
+++ b/windows/RCTPdf/ReactPackageProvider.h
@@ -0,0 +1,16 @@
+#pragma once
+#include "ReactPackageProvider.g.h"
+
+using namespace winrt::Microsoft::ReactNative;
+
+namespace winrt::RCTPdf::implementation {
+ struct ReactPackageProvider : ReactPackageProviderT {
+ ReactPackageProvider() = default;
+ void CreatePackage(IReactPackageBuilder const &packageBuilder) noexcept;
+ };
+}
+
+namespace winrt::RCTPdf::factory_implementation {
+ struct ReactPackageProvider : ReactPackageProviderT {};
+}
+
diff --git a/windows/RCTPdf/ReactPackageProvider.idl b/windows/RCTPdf/ReactPackageProvider.idl
new file mode 100644
index 00000000..8f2b9f54
--- /dev/null
+++ b/windows/RCTPdf/ReactPackageProvider.idl
@@ -0,0 +1,9 @@
+namespace RCTPdf
+{
+ [webhosthidden]
+ [default_interface]
+ runtimeclass ReactPackageProvider : Microsoft.ReactNative.IReactPackageProvider
+ {
+ ReactPackageProvider();
+ };
+}
diff --git a/windows/RCTPdf/packages.config b/windows/RCTPdf/packages.config
new file mode 100644
index 00000000..1447e714
--- /dev/null
+++ b/windows/RCTPdf/packages.config
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/windows/RCTPdf/pch.cpp b/windows/RCTPdf/pch.cpp
new file mode 100644
index 00000000..bcb5590b
--- /dev/null
+++ b/windows/RCTPdf/pch.cpp
@@ -0,0 +1 @@
+#include "pch.h"
diff --git a/windows/RCTPdf/pch.h b/windows/RCTPdf/pch.h
new file mode 100644
index 00000000..ebe005ec
--- /dev/null
+++ b/windows/RCTPdf/pch.h
@@ -0,0 +1,28 @@
+#pragma once
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
diff --git a/windows/README.md b/windows/README.md
new file mode 100644
index 00000000..8bc2611b
--- /dev/null
+++ b/windows/README.md
@@ -0,0 +1,23 @@
+# react-native-pdf Windows Implementation
+
+Since the module uses react-native-progress-view, it also needs to be referenced in the App:
+- Open your solution in Visual Studio 2019 (eg. `windows\yourapp.sln`)
+- Right-click Solution icon in Solution Explorer > Add > Existing Project...
+- Add `node_modules\@react-native-community\progress-view\windows\progress-view\progress-view.vcxproj`
+- If running RNW 0.62: add `node_modules\react-native-pdf\windows\RCTPdf\RCTPdf.vcxproj`
+- Right-click main application project > Add > Reference...
+ - Select `progress-view` and in Solution Projects
+ - If running 0.62, also select `RCTPdf`
+- In app `pch.h` add `#include "winrt/progress-view.h"` and `#include "winrt/RCTPdf.h"`
+- In `App.cpp` add `PackageProviders().Append(winrt::progress-view::ReactPackageProvider());` before `InitializeComponent();`
+- If running RNW 0.62, also add `PackageProviders().Append(winrt::RCTPdf::ReactPackageProvider());`
+
+
+## Bundling PDFs with the app
+To add a `test.pdf` like in the example add:
+```
+
+ true
+
+```
+in the app `.vcxproj` file, before ``.