diff --git a/examples/bare/App.minimal.js b/examples/bare/App.minimal.js new file mode 100644 index 0000000000..1cf9abc6f2 --- /dev/null +++ b/examples/bare/App.minimal.js @@ -0,0 +1,380 @@ +/** + * React Native Video Demo for Win32 + * @format + */ + +import React, {useState, useCallback} from 'react'; +import { + View, + Text, + StyleSheet, + TouchableOpacity, + Platform, + NativeModules, +} from 'react-native'; + +// File picker for Windows +const {FilePicker} = NativeModules; + +export default function MinimalApp() { + const [paused, setPaused] = useState(true); + const [currentTime, setCurrentTime] = useState(0); + const [duration, setDuration] = useState(0); + const [selectedVideo, setSelectedVideo] = useState(null); + const [isPlaying, setIsPlaying] = useState(false); + + const formatTime = (seconds) => { + const mins = Math.floor(seconds / 60); + const secs = Math.floor(seconds % 60); + return `${mins}:${secs < 10 ? '0' : ''}${secs}`; + }; + + const progressPercent = duration > 0 ? (currentTime / duration) * 100 : 0; + + const handleBrowse = useCallback(async () => { + // For now, simulate file selection with a prompt + // In a full implementation, this would use a native file picker + const sampleVideos = [ + {name: 'Sample Video 1.mp4', path: 'C:\\Videos\\sample1.mp4', duration: 180}, + {name: 'Sample Video 2.mp4', path: 'C:\\Videos\\sample2.mp4', duration: 240}, + {name: 'Big Buck Bunny.mp4', path: 'C:\\Videos\\bunny.mp4', duration: 596}, + ]; + // Cycle through sample videos for demo + const currentIndex = selectedVideo + ? sampleVideos.findIndex(v => v.path === selectedVideo.path) + : -1; + const nextIndex = (currentIndex + 1) % sampleVideos.length; + const video = sampleVideos[nextIndex]; + setSelectedVideo(video); + setDuration(video.duration); + setCurrentTime(0); + setIsPlaying(false); + setPaused(true); + }, [selectedVideo]); + + const handlePlay = useCallback(() => { + if (selectedVideo) { + setIsPlaying(true); + setPaused(false); + // Simulate playback progress + const interval = setInterval(() => { + setCurrentTime((prev) => { + if (prev >= duration) { + clearInterval(interval); + setIsPlaying(false); + setPaused(true); + return 0; + } + return prev + 1; + }); + }, 1000); + // Store interval ID for cleanup + window.playbackInterval = interval; + } + }, [selectedVideo, duration]); + + const handlePause = useCallback(() => { + setIsPlaying(false); + setPaused(true); + if (window.playbackInterval) { + clearInterval(window.playbackInterval); + } + }, []); + + const handleStop = useCallback(() => { + setIsPlaying(false); + setPaused(true); + setCurrentTime(0); + if (window.playbackInterval) { + clearInterval(window.playbackInterval); + } + }, []); + + const handleSeek = useCallback((position) => { + // position is 0-1 representing percentage + const newTime = Math.floor(position * duration); + setCurrentTime(newTime); + }, [duration]); + + return ( + + React Native Video Player + + {/* Video Display Area */} + + {selectedVideo ? ( + + {isPlaying ? ( + ▶ Playing... + ) : ( + 🎬 + )} + {selectedVideo.name} + + ) : ( + + 📁 + No video selected + Click "Browse" to select a video + + )} + + + {/* Browse Button - Right below video */} + + 📂 + Browse This Computer + + + {/* File Info */} + {selectedVideo && ( + + Selected: + {selectedVideo.name} + + )} + + {/* Progress Bar */} + + {formatTime(currentTime)} + { + const {locationX} = e.nativeEvent; + const width = 300; // approximate width + handleSeek(locationX / width); + }} + > + + + + {formatTime(duration)} + + + {/* Playback Controls */} + + + + Stop + + + {isPlaying ? ( + + + Pause + + ) : ( + + + Play + + )} + + + + End + + + + ); +} + +const styles = StyleSheet.create({ + container: { + flex: 1, + backgroundColor: '#1a1a2e', + padding: 20, + alignItems: 'center', + }, + title: { + fontSize: 28, + fontWeight: 'bold', + color: '#ffffff', + marginBottom: 20, + marginTop: 10, + }, + videoContainer: { + width: '100%', + aspectRatio: 16 / 9, + backgroundColor: '#000', + borderRadius: 12, + overflow: 'hidden', + justifyContent: 'center', + alignItems: 'center', + maxWidth: 600, + }, + videoPlaceholder: { + flex: 1, + justifyContent: 'center', + alignItems: 'center', + backgroundColor: '#0a0a15', + width: '100%', + }, + playingText: { + fontSize: 32, + color: '#0078d7', + marginBottom: 10, + }, + videoIcon: { + fontSize: 64, + marginBottom: 10, + }, + videoName: { + fontSize: 16, + color: '#ffffff', + fontWeight: '500', + }, + noVideoPlaceholder: { + flex: 1, + justifyContent: 'center', + alignItems: 'center', + width: '100%', + }, + noVideoIcon: { + fontSize: 48, + marginBottom: 10, + opacity: 0.5, + }, + noVideoText: { + fontSize: 18, + color: '#666', + marginBottom: 5, + }, + noVideoHint: { + fontSize: 14, + color: '#444', + }, + progressSection: { + flexDirection: 'row', + alignItems: 'center', + width: '100%', + maxWidth: 600, + marginTop: 15, + paddingHorizontal: 10, + }, + timeText: { + color: '#ffffff', + fontSize: 14, + width: 50, + textAlign: 'center', + }, + progressBar: { + flex: 1, + height: 8, + backgroundColor: '#333', + borderRadius: 4, + marginHorizontal: 10, + position: 'relative', + }, + progressFill: { + height: '100%', + backgroundColor: '#0078d7', + borderRadius: 4, + }, + progressThumb: { + position: 'absolute', + top: -4, + width: 16, + height: 16, + backgroundColor: '#ffffff', + borderRadius: 8, + marginLeft: -8, + }, + controls: { + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'center', + marginTop: 20, + gap: 20, + }, + controlButton: { + backgroundColor: '#333', + paddingHorizontal: 20, + paddingVertical: 12, + borderRadius: 8, + alignItems: 'center', + minWidth: 70, + }, + controlButtonDisabled: { + opacity: 0.5, + }, + controlIcon: { + fontSize: 24, + color: '#ffffff', + }, + controlLabel: { + fontSize: 12, + color: '#aaa', + marginTop: 4, + }, + playButton: { + backgroundColor: '#0078d7', + paddingHorizontal: 30, + paddingVertical: 15, + borderRadius: 12, + alignItems: 'center', + minWidth: 100, + }, + playIcon: { + fontSize: 32, + color: '#ffffff', + }, + playLabel: { + fontSize: 14, + color: '#ffffff', + fontWeight: 'bold', + marginTop: 4, + }, + browseButton: { + flexDirection: 'row', + alignItems: 'center', + backgroundColor: '#0078d7', + paddingHorizontal: 24, + paddingVertical: 12, + borderRadius: 8, + marginTop: 15, + marginBottom: 5, + }, + browseIcon: { + fontSize: 20, + marginRight: 10, + }, + browseText: { + fontSize: 16, + color: '#ffffff', + fontWeight: 'bold', + }, + fileInfo: { + flexDirection: 'row', + marginTop: 8, + marginBottom: 10, + padding: 8, + backgroundColor: '#252542', + borderRadius: 6, + }, + fileInfoLabel: { + fontSize: 13, + color: '#888', + }, + fileInfoPath: { + fontSize: 13, + color: '#0078d7', + fontWeight: '500', + }, +}); diff --git a/examples/bare/NuGet.config b/examples/bare/NuGet.config new file mode 100644 index 0000000000..fe459fedd6 --- /dev/null +++ b/examples/bare/NuGet.config @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/examples/bare/build_win32.bat b/examples/bare/build_win32.bat new file mode 100644 index 0000000000..a4f3955cb2 --- /dev/null +++ b/examples/bare/build_win32.bat @@ -0,0 +1,5 @@ +@echo off +cd /d %~dp0 +rmdir /s /q node_modules\react-native-windows\target 2>nul +rmdir /s /q node_modules\react-native-windows\build 2>nul +"C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Current\Bin\amd64\MSBuild.exe" windows\BareExample.sln /p:Configuration=Debug /p:Platform=x64 /m /v:minimal diff --git a/examples/bare/index.js b/examples/bare/index.js index 8c4bf6dbac..c901463d23 100644 --- a/examples/bare/index.js +++ b/examples/bare/index.js @@ -3,9 +3,7 @@ */ import {AppRegistry} from 'react-native'; -import BasicExample from 'common/BasicExample'; +import MinimalApp from './App.minimal'; import {name as appName} from './app.json'; -import DRMExample from 'common/DRMExample'; -AppRegistry.registerComponent(appName, () => BasicExample); -AppRegistry.registerComponent('DRMExample', () => DRMExample); +AppRegistry.registerComponent(appName, () => MinimalApp); diff --git a/examples/bare/jest.config.windows.js b/examples/bare/jest.config.windows.js new file mode 100644 index 0000000000..4ae04e8b48 --- /dev/null +++ b/examples/bare/jest.config.windows.js @@ -0,0 +1,3 @@ +const config = {}; + +module.exports = require('@rnx-kit/jest-preset')('windows', config); diff --git a/examples/bare/metro.config.js b/examples/bare/metro.config.js index 16b3913650..f2376e7bdb 100644 --- a/examples/bare/metro.config.js +++ b/examples/bare/metro.config.js @@ -1,6 +1,9 @@ const path = require('path'); const {makeMetroConfig} = require('@rnx-kit/metro-config'); +// Path to the root react-native-video package +const rnvPath = path.resolve(__dirname, '../..'); + module.exports = makeMetroConfig({ transformer: { getTransformOptions: async () => ({ @@ -16,7 +19,10 @@ module.exports = makeMetroConfig({ extraNodeModules: { common: path.resolve(__dirname, '../common'), 'react-native-video': path.resolve(__dirname, '../../lib/'), - '@react-native-picker/picker': path.resolve(__dirname, 'node_modules/@react-native-picker/picker'), + '@react-native-picker/picker': path.resolve( + __dirname, + 'node_modules/@react-native-picker/picker', + ), }, }, watchFolders: [ diff --git a/examples/bare/package.json b/examples/bare/package.json index 47328782a7..355353f0b3 100644 --- a/examples/bare/package.json +++ b/examples/bare/package.json @@ -15,11 +15,11 @@ "start": "react-native start", "test": "jest", "visionos": "react-native run-visionos", - "windows": "react-native run-windows --sln windows/BareExample.sln" + "windows": "npx @react-native-community/cli run-windows", + "test:windows": "jest --config jest.config.windows.js" }, "dependencies": { "@callstack/react-native-visionos": "^0.78.0", - "@react-native-picker/picker": "2.11.0", "react": "19.0.0", "react-native": "^0.78.0", "react-native-video": "link:../..", @@ -44,9 +44,17 @@ "prettier": "2.8.8", "react-native-test-app": "^4.1.4", "react-test-renderer": "19.0.0", - "typescript": "5.0.4" + "typescript": "5.0.4", + "@rnx-kit/jest-preset": "^0.1.17" }, "engines": { "node": ">=18" + }, + "react-native-windows": { + "init-windows": { + "name": "BareExample", + "namespace": "BareExample", + "template": "cpp-app" + } } } diff --git a/examples/bare/patches/@react-native-picker+picker+2.11.0.patch b/examples/bare/patches/@react-native-picker+picker+2.11.0.patch deleted file mode 100644 index ad657e06d4..0000000000 --- a/examples/bare/patches/@react-native-picker+picker+2.11.0.patch +++ /dev/null @@ -1,21 +0,0 @@ -diff --git a/node_modules/@react-native-picker/picker/RNCPicker.podspec b/node_modules/@react-native-picker/picker/RNCPicker.podspec -index bfdf16c..bdc9c7c 100644 ---- a/node_modules/@react-native-picker/picker/RNCPicker.podspec -+++ b/node_modules/@react-native-picker/picker/RNCPicker.podspec -@@ -12,7 +12,7 @@ Pod::Spec.new do |s| - - s.authors = package['author'] - s.homepage = package['homepage'] -- s.platforms = { :ios => "9.0", :osx => "10.14" } -+ s.platforms = { :ios => "9.0", :osx => "10.14", :visionos => "1.0" } - - s.source = { :git => "https://github.com/react-native-picker/picker.git", :tag => "v#{s.version}" } - -@@ -25,6 +25,7 @@ Pod::Spec.new do |s| - else - s.ios.source_files = "ios/**/*.{h,m,mm}" - s.osx.source_files = "macos/**/*.{h,m,mm}" -+ s.visionos.source_files = "ios/**/*.{h,m,mm}" - end - - s.dependency 'React-Core' diff --git a/examples/bare/react-native.config.js b/examples/bare/react-native.config.js index 9a219f6cf4..6915c6498c 100644 --- a/examples/bare/react-native.config.js +++ b/examples/bare/react-native.config.js @@ -1,16 +1,12 @@ const project = (() => { try { - const { configureProjects } = require("react-native-test-app"); + const {configureProjects} = require('react-native-test-app'); return configureProjects({ android: { - sourceDir: "android", + sourceDir: 'android', }, ios: { - sourceDir: "ios", - }, - windows: { - sourceDir: "windows", - solutionFile: "windows/BareExample.sln", + sourceDir: 'ios', }, }); } catch (_) { @@ -19,5 +15,29 @@ const project = (() => { })(); module.exports = { - ...(project ? { project } : undefined), + ...(project ? {project} : undefined), + // Disable react-native-video autolink for Windows (Win32 apps need manual loading) + // Disable @react-native-picker/picker for Windows (no Windows implementation) + dependencies: { + 'react-native-video': { + platforms: { + windows: null, + }, + }, + '@react-native-picker/picker': { + platforms: { + windows: null, + }, + }, + }, + project: { + ...project, + windows: { + sourceDir: 'windows', + solutionFile: 'BareExampleApp.sln', + project: { + projectFile: 'BareExampleApp/BareExampleApp.vcxproj', + }, + }, + }, }; diff --git a/examples/bare/windows/.gitignore b/examples/bare/windows/.gitignore index fb81ae232b..691c954a38 100644 --- a/examples/bare/windows/.gitignore +++ b/examples/bare/windows/.gitignore @@ -1,33 +1,47 @@ -.vs/ +*AppPackages* +*BundleArtifacts* -# User-specific files -*.suo -*.user -*.sln.docstates +# NuGet packages - restored via nuget restore +packages/ -# Build results -ARM64/ -AppPackages/ -[Bb]in/ -[Dd]ebug/ -[Dd]ebugPublic/ -[Oo]bj/ -[Rr]elease/ -[Rr]eleases/ -bld/ -build/ -x64/ -x86/ +# Package lock files +packages.lock.json -# NuGet Packages Directory -packages/ +#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 +.vs/ +# Visual C++ cache files +#Files generated by the VS build **/Generated Files/** -*.binlog -*.hprof -*.sln -ExperimentalFeatures.props -NuGet.Config -dist/ -msbuild.binlog -node_modules/ diff --git a/examples/bare/windows/BareExampleApp.Package/BareExampleApp.Package.wapproj b/examples/bare/windows/BareExampleApp.Package/BareExampleApp.Package.wapproj new file mode 100644 index 0000000000..8a28485695 --- /dev/null +++ b/examples/bare/windows/BareExampleApp.Package/BareExampleApp.Package.wapproj @@ -0,0 +1,78 @@ + + + + + {3c6c793f-5b27-439d-8a02-b03f61f84332} + en-US + ..\BareExampleApp\BareExampleApp.vcxproj + NativeOnly + NativeOnly + + + $([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), 'node_modules\react-native-windows\package.json'))\node_modules\react-native-windows\ + + + + $(MSBuildExtensionsPath)\Microsoft\DesktopBridge\ + + + + + Debug + x86 + + + Release + x86 + + + Debug + x64 + + + Release + x64 + + + Debug + ARM64 + + + Release + ARM64 + + + + + + + + Designer + + + + + + + + + + + + + + True + + + + + + + + + This project references targets in your node_modules\react-native-windows folder that are missing. The missing file is {0}. + + + + + diff --git a/examples/bare/windows/BareExampleApp.Package/Images/LockScreenLogo.scale-200.png b/examples/bare/windows/BareExampleApp.Package/Images/LockScreenLogo.scale-200.png new file mode 100644 index 0000000000..735f57adb5 Binary files /dev/null and b/examples/bare/windows/BareExampleApp.Package/Images/LockScreenLogo.scale-200.png differ diff --git a/examples/bare/windows/BareExampleApp.Package/Images/SplashScreen.scale-200.png b/examples/bare/windows/BareExampleApp.Package/Images/SplashScreen.scale-200.png new file mode 100644 index 0000000000..023e7f1fed Binary files /dev/null and b/examples/bare/windows/BareExampleApp.Package/Images/SplashScreen.scale-200.png differ diff --git a/examples/bare/windows/BareExampleApp.Package/Images/Square150x150Logo.scale-200.png b/examples/bare/windows/BareExampleApp.Package/Images/Square150x150Logo.scale-200.png new file mode 100644 index 0000000000..af49fec1a5 Binary files /dev/null and b/examples/bare/windows/BareExampleApp.Package/Images/Square150x150Logo.scale-200.png differ diff --git a/examples/bare/windows/BareExampleApp.Package/Images/Square44x44Logo.scale-200.png b/examples/bare/windows/BareExampleApp.Package/Images/Square44x44Logo.scale-200.png new file mode 100644 index 0000000000..ce342a2ec8 Binary files /dev/null and b/examples/bare/windows/BareExampleApp.Package/Images/Square44x44Logo.scale-200.png differ diff --git a/examples/bare/windows/BareExampleApp.Package/Images/Square44x44Logo.targetsize-24_altform-unplated.png b/examples/bare/windows/BareExampleApp.Package/Images/Square44x44Logo.targetsize-24_altform-unplated.png new file mode 100644 index 0000000000..f6c02ce97e Binary files /dev/null and b/examples/bare/windows/BareExampleApp.Package/Images/Square44x44Logo.targetsize-24_altform-unplated.png differ diff --git a/examples/bare/windows/BareExampleApp.Package/Images/StoreLogo.png b/examples/bare/windows/BareExampleApp.Package/Images/StoreLogo.png new file mode 100644 index 0000000000..7385b56c0e Binary files /dev/null and b/examples/bare/windows/BareExampleApp.Package/Images/StoreLogo.png differ diff --git a/examples/bare/windows/BareExampleApp.Package/Images/Wide310x150Logo.scale-200.png b/examples/bare/windows/BareExampleApp.Package/Images/Wide310x150Logo.scale-200.png new file mode 100644 index 0000000000..288995b397 Binary files /dev/null and b/examples/bare/windows/BareExampleApp.Package/Images/Wide310x150Logo.scale-200.png differ diff --git a/examples/bare/windows/BareExampleApp.Package/Package.appxmanifest b/examples/bare/windows/BareExampleApp.Package/Package.appxmanifest new file mode 100644 index 0000000000..6a9dbabc18 --- /dev/null +++ b/examples/bare/windows/BareExampleApp.Package/Package.appxmanifest @@ -0,0 +1,49 @@ + + + + + + + + BareExampleApp + protikbiswas + Images\StoreLogo.png + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/bare/windows/BareExampleApp.sln b/examples/bare/windows/BareExampleApp.sln new file mode 100644 index 0000000000..7dc957aab8 --- /dev/null +++ b/examples/bare/windows/BareExampleApp.sln @@ -0,0 +1,77 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.3.32929.385 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{C7167F0D-BC9F-4E6E-AFE1-012C56B48DB5}") = "BareExampleApp.Package", "BareExampleApp.Package\BareExampleApp.Package.wapproj", "{3C6C793F-5B27-439D-8A02-B03F61F84332}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BareExampleApp", "BareExampleApp\BareExampleApp.vcxproj", "{B1D92238-A3A1-4729-9012-35AFEAC8FAB8}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ReactNativeVideoCPP", "..\..\..\windows\ReactNativeVideoCPP\ReactNativeVideoCPP.vcxproj", "{0D1E54D3-4BE1-4DAF-98BF-124C28C85014}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Debug|ARM64 = Debug|ARM64 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + Release|ARM64 = Release|ARM64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {3C6C793F-5B27-439D-8A02-B03F61F84332}.Debug|x64.ActiveCfg = Debug|x64 + {3C6C793F-5B27-439D-8A02-B03F61F84332}.Debug|x64.Build.0 = Debug|x64 + {3C6C793F-5B27-439D-8A02-B03F61F84332}.Debug|x64.Deploy.0 = Debug|x64 + {3C6C793F-5B27-439D-8A02-B03F61F84332}.Debug|x86.ActiveCfg = Debug|x86 + {3C6C793F-5B27-439D-8A02-B03F61F84332}.Debug|x86.Build.0 = Debug|x86 + {3C6C793F-5B27-439D-8A02-B03F61F84332}.Debug|x86.Deploy.0 = Debug|x86 + {3C6C793F-5B27-439D-8A02-B03F61F84332}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {3C6C793F-5B27-439D-8A02-B03F61F84332}.Debug|ARM64.Build.0 = Debug|ARM64 + {3C6C793F-5B27-439D-8A02-B03F61F84332}.Debug|ARM64.Deploy.0 = Debug|ARM64 + {3C6C793F-5B27-439D-8A02-B03F61F84332}.Release|x64.ActiveCfg = Release|x64 + {3C6C793F-5B27-439D-8A02-B03F61F84332}.Release|x64.Build.0 = Release|x64 + {3C6C793F-5B27-439D-8A02-B03F61F84332}.Release|x64.Deploy.0 = Release|x64 + {3C6C793F-5B27-439D-8A02-B03F61F84332}.Release|x86.ActiveCfg = Release|x86 + {3C6C793F-5B27-439D-8A02-B03F61F84332}.Release|x86.Build.0 = Release|x86 + {3C6C793F-5B27-439D-8A02-B03F61F84332}.Release|x86.Deploy.0 = Release|x86 + {3C6C793F-5B27-439D-8A02-B03F61F84332}.Release|ARM64.ActiveCfg = Release|ARM64 + {3C6C793F-5B27-439D-8A02-B03F61F84332}.Release|ARM64.Build.0 = Release|ARM64 + {3C6C793F-5B27-439D-8A02-B03F61F84332}.Release|ARM64.Deploy.0 = Release|ARM64 + {B1D92238-A3A1-4729-9012-35AFEAC8FAB8}.Debug|x64.ActiveCfg = Debug|x64 + {B1D92238-A3A1-4729-9012-35AFEAC8FAB8}.Debug|x64.Build.0 = Debug|x64 + {B1D92238-A3A1-4729-9012-35AFEAC8FAB8}.Debug|x64.Deploy.0 = Debug|x64 + {B1D92238-A3A1-4729-9012-35AFEAC8FAB8}.Debug|x86.ActiveCfg = Debug|Win32 + {B1D92238-A3A1-4729-9012-35AFEAC8FAB8}.Debug|x86.Build.0 = Debug|Win32 + {B1D92238-A3A1-4729-9012-35AFEAC8FAB8}.Debug|x86.Deploy.0 = Debug|Win32 + {B1D92238-A3A1-4729-9012-35AFEAC8FAB8}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {B1D92238-A3A1-4729-9012-35AFEAC8FAB8}.Debug|ARM64.Build.0 = Debug|ARM64 + {B1D92238-A3A1-4729-9012-35AFEAC8FAB8}.Debug|ARM64.Deploy.0 = Debug|ARM64 + {B1D92238-A3A1-4729-9012-35AFEAC8FAB8}.Release|x64.ActiveCfg = Release|x64 + {B1D92238-A3A1-4729-9012-35AFEAC8FAB8}.Release|x64.Build.0 = Release|x64 + {B1D92238-A3A1-4729-9012-35AFEAC8FAB8}.Release|x64.Deploy.0 = Release|x64 + {B1D92238-A3A1-4729-9012-35AFEAC8FAB8}.Release|x86.ActiveCfg = Release|Win32 + {B1D92238-A3A1-4729-9012-35AFEAC8FAB8}.Release|x86.Build.0 = Release|Win32 + {B1D92238-A3A1-4729-9012-35AFEAC8FAB8}.Release|x86.Deploy.0 = Release|Win32 + {B1D92238-A3A1-4729-9012-35AFEAC8FAB8}.Release|ARM64.ActiveCfg = Release|ARM64 + {B1D92238-A3A1-4729-9012-35AFEAC8FAB8}.Release|ARM64.Build.0 = Release|ARM64 + {B1D92238-A3A1-4729-9012-35AFEAC8FAB8}.Release|ARM64.Deploy.0 = Release|ARM64 + {0D1E54D3-4BE1-4DAF-98BF-124C28C85014}.Debug|x64.ActiveCfg = Debug|x64 + {0D1E54D3-4BE1-4DAF-98BF-124C28C85014}.Debug|x64.Build.0 = Debug|x64 + {0D1E54D3-4BE1-4DAF-98BF-124C28C85014}.Debug|x86.ActiveCfg = Debug|Win32 + {0D1E54D3-4BE1-4DAF-98BF-124C28C85014}.Debug|x86.Build.0 = Debug|Win32 + {0D1E54D3-4BE1-4DAF-98BF-124C28C85014}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {0D1E54D3-4BE1-4DAF-98BF-124C28C85014}.Debug|ARM64.Build.0 = Debug|ARM64 + {0D1E54D3-4BE1-4DAF-98BF-124C28C85014}.Release|x64.ActiveCfg = Release|x64 + {0D1E54D3-4BE1-4DAF-98BF-124C28C85014}.Release|x64.Build.0 = Release|x64 + {0D1E54D3-4BE1-4DAF-98BF-124C28C85014}.Release|x86.ActiveCfg = Release|Win32 + {0D1E54D3-4BE1-4DAF-98BF-124C28C85014}.Release|x86.Build.0 = Release|Win32 + {0D1E54D3-4BE1-4DAF-98BF-124C28C85014}.Release|ARM64.ActiveCfg = Release|ARM64 + {0D1E54D3-4BE1-4DAF-98BF-124C28C85014}.Release|ARM64.Build.0 = Release|ARM64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {D43FAD39-F619-437D-BB40-04A3982ACB6A} + EndGlobalSection +EndGlobal diff --git a/examples/bare/windows/BareExampleApp/.gitignore b/examples/bare/windows/BareExampleApp/.gitignore new file mode 100644 index 0000000000..82fabe9662 --- /dev/null +++ b/examples/bare/windows/BareExampleApp/.gitignore @@ -0,0 +1 @@ +/Bundle \ No newline at end of file diff --git a/examples/bare/windows/BareExampleApp/App.cpp b/examples/bare/windows/BareExampleApp/App.cpp new file mode 100644 index 0000000000..92c1253d15 --- /dev/null +++ b/examples/bare/windows/BareExampleApp/App.cpp @@ -0,0 +1,87 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "pch.h" +#include "App.xaml.g.h" + +#include "NativeModules.h" +#include + +using namespace winrt; +using namespace Windows::ApplicationModel; +using namespace Windows::ApplicationModel::Activation; +using namespace Windows::Foundation; +using namespace Windows::UI::Xaml; +using namespace Windows::UI::Xaml::Controls; +using namespace Windows::UI::Xaml::Navigation; +using namespace Microsoft::ReactNative; + +namespace winrt::BareExampleApp::implementation +{ + // A PackageProvider containing any turbo modules that is defined within this app project + struct CompReactPackageProvider + : winrt::implements { + void CreatePackage(IReactPackageBuilder const &packageBuilder) noexcept { + // For UWP, we don't use AddPackageProvider - packages are added directly to PackageProviders collection + } + }; + + struct App : AppT + { + App() + { +#if BUNDLE + JavaScriptBundleFile(L"index.windows"); + InstanceSettings().UseFastRefresh(false); +#else + JavaScriptBundleFile(L"index"); + InstanceSettings().UseFastRefresh(true); +#endif + +#if _DEBUG + InstanceSettings().UseDirectDebugger(true); + InstanceSettings().UseDeveloperSupport(true); +#else + InstanceSettings().UseDirectDebugger(false); + InstanceSettings().UseDeveloperSupport(false); +#endif + + // Register package providers + PackageProviders().Append(winrt::make()); + PackageProviders().Append(winrt::BareExample::ReactPackageProvider()); + + InitializeComponent(); + } + + void OnLaunched(LaunchActivatedEventArgs const& e) + { + super::OnLaunched(e); + auto frame = Window::Current().Content().try_as(); + if (frame == nullptr) + { + frame = Frame(); + Interop::TypeName typeName; + typeName.Name = L"Microsoft.ReactNative.ReactPage"; + typeName.Kind = Interop::TypeKind::Metadata; + frame.Navigate(typeName, box_value(L"BareExample")); + Window::Current().Content(frame); + } + + Window::Current().Activate(); + } + + void OnSuspending([[maybe_unused]] IInspectable const&, [[maybe_unused]] SuspendingEventArgs const& e) + { + // Save application state + } + + private: + using super = AppT; + }; +} + +int __stdcall wWinMain(HINSTANCE, HINSTANCE, PWSTR, int) +{ + Application::Start([](auto &&) { winrt::make(); }); + return 0; +} diff --git a/examples/bare/windows/BareExampleApp/App.xaml b/examples/bare/windows/BareExampleApp/App.xaml new file mode 100644 index 0000000000..dc38da3ff2 --- /dev/null +++ b/examples/bare/windows/BareExampleApp/App.xaml @@ -0,0 +1,6 @@ + + diff --git a/examples/bare/windows/BareExampleApp/AutolinkedNativeModules.g.cpp b/examples/bare/windows/BareExampleApp/AutolinkedNativeModules.g.cpp new file mode 100644 index 0000000000..5821cfddc5 --- /dev/null +++ b/examples/bare/windows/BareExampleApp/AutolinkedNativeModules.g.cpp @@ -0,0 +1,14 @@ +// AutolinkedNativeModules.g.cpp contents generated by "npx @react-native-community/cli autolink-windows" +// clang-format off +#include "pch.h" +#include "AutolinkedNativeModules.g.h" + +namespace winrt::Microsoft::ReactNative +{ + +void RegisterAutolinkedNativeModulePackages(winrt::Windows::Foundation::Collections::IVector const& packageProviders) +{ + UNREFERENCED_PARAMETER(packageProviders); +} + +} diff --git a/examples/bare/windows/BareExampleApp/AutolinkedNativeModules.g.h b/examples/bare/windows/BareExampleApp/AutolinkedNativeModules.g.h new file mode 100644 index 0000000000..a3da81ddd8 --- /dev/null +++ b/examples/bare/windows/BareExampleApp/AutolinkedNativeModules.g.h @@ -0,0 +1,10 @@ +// AutolinkedNativeModules.g.h contents generated by "npx @react-native-community/cli autolink-windows" +// clang-format off +#pragma once + +namespace winrt::Microsoft::ReactNative +{ + +void RegisterAutolinkedNativeModulePackages(winrt::Windows::Foundation::Collections::IVector const& packageProviders); + +} diff --git a/examples/bare/windows/BareExampleApp/AutolinkedNativeModules.g.props b/examples/bare/windows/BareExampleApp/AutolinkedNativeModules.g.props new file mode 100644 index 0000000000..0dd8b33c1e --- /dev/null +++ b/examples/bare/windows/BareExampleApp/AutolinkedNativeModules.g.props @@ -0,0 +1,6 @@ + + + + + + diff --git a/examples/bare/windows/BareExampleApp/AutolinkedNativeModules.g.targets b/examples/bare/windows/BareExampleApp/AutolinkedNativeModules.g.targets new file mode 100644 index 0000000000..6a85ec51cd --- /dev/null +++ b/examples/bare/windows/BareExampleApp/AutolinkedNativeModules.g.targets @@ -0,0 +1,6 @@ + + + + + + diff --git a/examples/bare/windows/BareExampleApp/BareExampleApp.cpp b/examples/bare/windows/BareExampleApp/BareExampleApp.cpp new file mode 100644 index 0000000000..9c1fc5ee6b --- /dev/null +++ b/examples/bare/windows/BareExampleApp/BareExampleApp.cpp @@ -0,0 +1,82 @@ +// BareExampleApp.cpp : Defines the entry point for the application. +// + +#include "pch.h" +#include "BareExampleApp.h" + +#include "AutolinkedNativeModules.g.h" + +#include "NativeModules.h" + +// A PackageProvider containing any turbo modules you define within this app project +struct CompReactPackageProvider + : winrt::implements { + public: // IReactPackageProvider + void CreatePackage(winrt::Microsoft::ReactNative::IReactPackageBuilder const &packageBuilder) noexcept { + AddAttributedModules(packageBuilder, true); + } +}; + +// The entry point of the Win32 application +_Use_decl_annotations_ int CALLBACK WinMain(HINSTANCE instance, HINSTANCE, PSTR /* commandLine */, int showCmd) { + // Initialize WinRT + winrt::init_apartment(winrt::apartment_type::single_threaded); + + // Enable per monitor DPI scaling + SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2); + + // Find the path hosting the app exe file + WCHAR appDirectory[MAX_PATH]; + GetModuleFileNameW(NULL, appDirectory, MAX_PATH); + PathCchRemoveFileSpec(appDirectory, MAX_PATH); + + // Create a ReactNativeWin32App with the ReactNativeAppBuilder + auto reactNativeWin32App{winrt::Microsoft::ReactNative::ReactNativeAppBuilder().Build()}; + + // Configure the initial InstanceSettings for the app's ReactNativeHost + auto settings{reactNativeWin32App.ReactNativeHost().InstanceSettings()}; + // Register any autolinked native modules + RegisterAutolinkedNativeModulePackages(settings.PackageProviders()); + // Register any native modules defined within this app project + settings.PackageProviders().Append(winrt::make()); + +#if BUNDLE + // Load the JS bundle from a file (not Metro): + // Set the path (on disk) where the .bundle file is located + settings.BundleRootPath(std::wstring(L"file://").append(appDirectory).append(L"\\Bundle\\").c_str()); + // Set the name of the bundle file (without the .bundle extension) + settings.JavaScriptBundleFile(L"index.windows"); + // Disable hot reload + settings.UseFastRefresh(false); +#else + // Load the JS bundle from Metro + settings.JavaScriptBundleFile(L"index"); + // Enable hot reload + settings.UseFastRefresh(true); +#endif +#if _DEBUG + // For Debug builds + // Enable Direct Debugging of JS + settings.UseDirectDebugger(true); + // Enable the Developer Menu + settings.UseDeveloperSupport(true); +#else + // For Release builds: + // Disable Direct Debugging of JS + settings.UseDirectDebugger(false); + // Disable the Developer Menu + settings.UseDeveloperSupport(false); +#endif + + // Get the AppWindow so we can configure its initial title and size + auto appWindow{reactNativeWin32App.AppWindow()}; + appWindow.Title(L"BareExample"); + appWindow.Resize({1000, 1000}); + + // Get the ReactViewOptions so we can set the initial RN component to load + auto viewOptions{reactNativeWin32App.ReactViewOptions()}; + viewOptions.ComponentName(L"BareExample"); + + // Start the app + reactNativeWin32App.Start(); +} diff --git a/examples/bare/windows/BareExampleApp/BareExampleApp.h b/examples/bare/windows/BareExampleApp/BareExampleApp.h new file mode 100644 index 0000000000..d00d47e788 --- /dev/null +++ b/examples/bare/windows/BareExampleApp/BareExampleApp.h @@ -0,0 +1,3 @@ +#pragma once + +#include "resource.h" diff --git a/examples/bare/windows/BareExampleApp/BareExampleApp.ico b/examples/bare/windows/BareExampleApp/BareExampleApp.ico new file mode 100644 index 0000000000..b3ec03bd61 Binary files /dev/null and b/examples/bare/windows/BareExampleApp/BareExampleApp.ico differ diff --git a/examples/bare/windows/BareExampleApp/BareExampleApp.rc b/examples/bare/windows/BareExampleApp/BareExampleApp.rc new file mode 100644 index 0000000000..5c3e4acd8c Binary files /dev/null and b/examples/bare/windows/BareExampleApp/BareExampleApp.rc differ diff --git a/examples/bare/windows/BareExampleApp/BareExampleApp.vcxproj b/examples/bare/windows/BareExampleApp/BareExampleApp.vcxproj new file mode 100644 index 0000000000..77707e5830 --- /dev/null +++ b/examples/bare/windows/BareExampleApp/BareExampleApp.vcxproj @@ -0,0 +1,135 @@ + + + + + + true + true + {B1D92238-A3A1-4729-9012-35AFEAC8FAB8} + BareExampleApp + Win32Proj + BareExample + 10.0 + en-US + 17.0 + false + + + $([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), 'node_modules\react-native-windows\package.json'))\node_modules\react-native-windows\ + + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + Debug + ARM64 + + + Release + ARM64 + + + + Application + Unicode + v143 + + + true + + + false + true + + + + + + + + + + + + + Use + pch.h + $(IntDir)pch.pch + Level4 + true + %(AdditionalOptions) /bigobj + 4453;28204 + + + shell32.lib;user32.lib;windowsapp.lib;%(AdditionalDependenices) + Windows + true + + + + + _DEBUG;%(PreprocessorDefinitions) + + + + + NDEBUG;%(PreprocessorDefinitions) + + + + + + + + + + + + + + + Create + Create + Create + Create + Create + Create + + + + + + + + + + + + + + + + + + This project references targets in your node_modules\react-native-windows folder. The missing file is {0}. + + + + + \ No newline at end of file diff --git a/examples/bare/windows/BareExampleApp/BareExampleApp.vcxproj.filters b/examples/bare/windows/BareExampleApp/BareExampleApp.vcxproj.filters new file mode 100644 index 0000000000..0a2c95da8e --- /dev/null +++ b/examples/bare/windows/BareExampleApp/BareExampleApp.vcxproj.filters @@ -0,0 +1,58 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + + + Resource Files + + + + + Resource Files + + + Resource Files + + + \ No newline at end of file diff --git a/examples/bare/windows/BareExampleApp/PropertySheet.props b/examples/bare/windows/BareExampleApp/PropertySheet.props new file mode 100644 index 0000000000..3791937697 --- /dev/null +++ b/examples/bare/windows/BareExampleApp/PropertySheet.props @@ -0,0 +1,10 @@ + + + + + + $(VC_IncludePath);$(WindowsSDK_IncludePath);$(MSBuildThisFileDirectory) + + + + diff --git a/examples/bare/windows/BareExampleApp/packages.config b/examples/bare/windows/BareExampleApp/packages.config new file mode 100644 index 0000000000..db381fbbf9 --- /dev/null +++ b/examples/bare/windows/BareExampleApp/packages.config @@ -0,0 +1,6 @@ + + + + + + diff --git a/examples/bare/windows/BareExampleApp/pch.cpp b/examples/bare/windows/BareExampleApp/pch.cpp new file mode 100644 index 0000000000..1d9f38c57d --- /dev/null +++ b/examples/bare/windows/BareExampleApp/pch.cpp @@ -0,0 +1 @@ +#include "pch.h" diff --git a/examples/bare/windows/BareExampleApp/pch.h b/examples/bare/windows/BareExampleApp/pch.h new file mode 100644 index 0000000000..364879013f --- /dev/null +++ b/examples/bare/windows/BareExampleApp/pch.h @@ -0,0 +1,38 @@ +// pch.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#pragma once + +#include "targetver.h" + +#define NOMINMAX 1 +#define WIN32_LEAN_AND_MEAN 1 +#define WINRT_LEAN_AND_MEAN 1 + +// Windows Header Files +#include +#undef GetCurrentTime +#include +#include + +// WinRT Header Files +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +// C RunTime Header Files +#include +#include +#include +#include + +// Reference additional headers your project requires here diff --git a/examples/bare/windows/BareExampleApp/resource.h b/examples/bare/windows/BareExampleApp/resource.h new file mode 100644 index 0000000000..d07e646987 --- /dev/null +++ b/examples/bare/windows/BareExampleApp/resource.h @@ -0,0 +1,17 @@ +// +// Microsoft Visual C++ generated include file. +// Used by BareExampleApp.rc + +#define IDI_ICON1 1008 +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS + +#define _APS_NO_MFC 130 +#define _APS_NEXT_RESOURCE_VALUE 129 +#define _APS_NEXT_COMMAND_VALUE 32771 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 110 +#endif +#endif diff --git a/examples/bare/windows/BareExampleApp/small.ico b/examples/bare/windows/BareExampleApp/small.ico new file mode 100644 index 0000000000..b3ec03bd61 Binary files /dev/null and b/examples/bare/windows/BareExampleApp/small.ico differ diff --git a/examples/bare/windows/BareExampleApp/targetver.h b/examples/bare/windows/BareExampleApp/targetver.h new file mode 100644 index 0000000000..87c0086de7 --- /dev/null +++ b/examples/bare/windows/BareExampleApp/targetver.h @@ -0,0 +1,8 @@ +#pragma once + +// Including SDKDDKVer.h defines the highest available Windows platform. + +// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and +// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. + +#include diff --git a/examples/bare/windows/Directory.Build.props b/examples/bare/windows/Directory.Build.props new file mode 100644 index 0000000000..78d6cd2287 --- /dev/null +++ b/examples/bare/windows/Directory.Build.props @@ -0,0 +1,9 @@ + + + + + + + None + + diff --git a/examples/bare/windows/Directory.Build.targets b/examples/bare/windows/Directory.Build.targets new file mode 100644 index 0000000000..a87c94e411 --- /dev/null +++ b/examples/bare/windows/Directory.Build.targets @@ -0,0 +1,14 @@ + + + + + None + + + + + + None + + + diff --git a/examples/bare/windows/ExperimentalFeatures.props b/examples/bare/windows/ExperimentalFeatures.props new file mode 100644 index 0000000000..a789f9d4e0 --- /dev/null +++ b/examples/bare/windows/ExperimentalFeatures.props @@ -0,0 +1,27 @@ + + + + + + true + + + true + + true + + + diff --git a/examples/bare/windows/README.md b/examples/bare/windows/README.md new file mode 100644 index 0000000000..7264a9f384 --- /dev/null +++ b/examples/bare/windows/README.md @@ -0,0 +1,67 @@ +# Bare Example - Windows (UWP) + +This folder contains the Windows UWP (Universal Windows Platform) application for the bare example of react-native-video. + +## Prerequisites + +- Visual Studio 2022 (or later) with: + - Universal Windows Platform development workload + - C++ (v143) Universal Windows Platform tools +- Windows 10 SDK (10.0.16299.0 or later) +- Node.js and npm/yarn + +## Building and Running + +1. Install dependencies from the repository root: + ```bash + cd /path/to/react-native-video + yarn install + ``` + +2. Install dependencies in the bare example: + ```bash + cd examples/bare + yarn install + ``` + +3. Restore NuGet packages: + - Open `BareExample.sln` in Visual Studio + - Right-click on the solution and select "Restore NuGet Packages" + +4. Build the solution: + - Press F7 or select Build > Build Solution + - Or from command line: `msbuild BareExample.sln /p:Configuration=Debug /p:Platform=x64` + +5. Run the application: + - Press F5 or select Debug > Start Debugging + - Or use the command: `yarn windows` + +## Running with Metro Bundler + +1. Start Metro bundler from the bare example directory: + ```bash + cd examples/bare + yarn start + ``` + +2. Run the Windows application: + ```bash + yarn windows + ``` + +## Project Structure + +- `BareExample.sln` - Visual Studio solution file +- `BareExampleApp/` - UWP application project (entry point) +- `BareExample/` - Native module library project + +## Troubleshooting + +### NuGet Package Errors +If one encounters NuGet package errors, try: +1. Close Visual Studio +2. Delete the `packages` folder +3. Reopen the solution and restore packages + +### Build Errors +Make sure to have the correct Windows SDK version installed and that your Visual Studio installation includes the C++ desktop development workload. diff --git a/examples/common/BasicExample.windows.tsx b/examples/common/BasicExample.windows.tsx index 5c66eebae2..9a54e60997 100644 --- a/examples/common/BasicExample.windows.tsx +++ b/examples/common/BasicExample.windows.tsx @@ -56,7 +56,8 @@ class VideoPlayer extends Component { { this.setState({rate: rate}); - }}> + }} + > {rate}x ); @@ -73,7 +74,8 @@ class VideoPlayer extends Component { { this.setState({resizeMode: resizeMode}); - }}> + }} + > {resizeMode} ); @@ -90,7 +92,8 @@ class VideoPlayer extends Component { { this.setState({volume: volume}); - }}> + }} + > {volume * 100}% ); @@ -106,7 +109,8 @@ class VideoPlayer extends Component { style={styles.fullScreen} onPress={() => { this.setState({paused: !this.state.paused}); - }}> + }} + >