Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/replace slider #39

Merged
merged 18 commits into from
Jan 21, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,16 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Changed

- Replaced slider component as a dependency of the seek bar.

### Fixed

- Fixed an issue where an app using the UI would crash when using the `SeekBar` component while streaming a live asset.

## 0.9.0 (2024-10-25)

### Changed
Expand Down
4 changes: 1 addition & 3 deletions doc/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,7 @@ The UI components also have a few non-transitive dependencies that are required
npm install \
@theoplayer/react-native-ui \
react-native-theoplayer \
react-native-svg \
@react-native-community/slider
react-native-svg
```

The package contains a number of transitive dependencies that contain native iOS and Android platform code
Expand All @@ -54,7 +53,6 @@ module.exports = {
dependencies: {
'react-native-google-cast': {},
'react-native-svg': {},
'@react-native-community/slider': {},
},
};
```
Expand Down
17 changes: 14 additions & 3 deletions example/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,20 @@ export default function App() {
player.addEventListener(PlayerEventType.SEEKED, console.log);
player.addEventListener(PlayerEventType.ENDED, console.log);
player.source = {
sources: {
src: 'https://cdn.theoplayer.com/video/adultswim/clip.m3u8',
type: 'application/x-mpegurl',
sources: [
{
src: 'https://cdn.theoplayer.com/video/dash/bbb_30fps/bbb_with_multiple_tiled_thumbnails.mpd',
type: 'application/dash+xml',
},
],
poster: 'https://cdn.theoplayer.com/video/big_buck_bunny/poster.jpg',
metadata: {
title: 'Big Buck Bunny',
subtitle: 'DASH - Thumbnails in manifest',
album: 'React-Native THEOplayer demos',
mediaUri: 'https://theoplayer.com',
displayIconUri: 'https://cdn.theoplayer.com/video/big_buck_bunny/poster.jpg',
artist: 'THEOplayer',
},
};

Expand Down
22 changes: 8 additions & 14 deletions example/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,19 @@
"android": "react-native run-android",
"ios": "react-native run-ios",
"web": "webpack-dev-server --config ./web/webpack.config.js --mode development",
"web-release": "webpack --config ./web/webpack.config.js --mode production",
"lint": "eslint \"**/*.{ts,tsx}\"",
"start": "react-native start",
"test": "jest"
},
"dependencies": {
"@react-native-community/slider": "^4.5.4",
"react": "18.3.1",
"react-dom": "18.3.1",
"react-native": "^0.75.4",
"react-native-google-cast": "^4.8.3",
"react-native-svg": "^15.8.0",
"react-native-svg-web": "^1.0.9",
"react-native-theoplayer": "^8.6.0",
"react-native-theoplayer": "^8.13.0",
"react-native-web": "^0.19.13",
"react-native-web-image-loader": "^0.1.1"
},
Expand All @@ -38,7 +38,7 @@
"copy-webpack-plugin": "^12.0.2",
"eslint": "^8.57.1",
"html-webpack-plugin": "^5.6.3",
"theoplayer": "^8.3.0",
"theoplayer": "^8.6.2",
"typescript": "5.0.4",
"webpack": "^5.95.0",
"webpack-cli": "^5.1.4",
Expand Down
45 changes: 28 additions & 17 deletions example/web/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,16 @@
const path = require('path');
const HTMLWebpackPlugin = require('html-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const NodePolyfillPlugin = require('node-polyfill-webpack-plugin');

const projectDirectory = path.resolve(__dirname, '..');
const projectDirectory = path.resolve(__dirname, '../..');

const appDirectory = path.resolve(__dirname, '..');

// A folder for any stub components we need in case there is no counterpart for it on react-native-web.
const stubDirectory = path.resolve(projectDirectory, './web/stub/');
const stubDirectory = path.resolve(appDirectory, './web/stub/');

const HTMLWebpackPluginConfig = new HTMLWebpackPlugin({
template: path.resolve(projectDirectory, './web/public/index.html'),
template: path.resolve(appDirectory, './web/public/index.html'),
filename: 'index.html',
inject: 'body',
});
Expand All @@ -26,12 +27,18 @@ const CopyWebpackPluginConfig = new CopyWebpackPlugin({
{
// Copy transmuxer worker files.
// THEOplayer will find them by setting `libraryLocation` in the playerConfiguration.
from: path.resolve(projectDirectory, './node_modules/theoplayer/THEOplayer.transmux.*').replace(/\\/g, '/'),
from: path.resolve(appDirectory, './node_modules/theoplayer/THEOplayer.transmux.*').replace(/\\/g, '/'),
to: `${libraryLocation}/[name][ext]`,
},
{
// Copy service worker
// THEOplayer will find them by setting `libraryLocation` in the playerConfiguration.
from: path.resolve(appDirectory, './node_modules/theoplayer/theoplayer.sw.js').replace(/\\/g, '/'),
to: `${libraryLocation}/[name][ext]`,
},
{
// Copy CSS files
from: path.resolve(projectDirectory, './web/public/*.css').replace(/\\/g, '/'),
from: path.resolve(appDirectory, './web/public/*.css').replace(/\\/g, '/'),
to: `[name][ext]`,
},
],
Expand All @@ -42,15 +49,18 @@ const CopyWebpackPluginConfig = new CopyWebpackPlugin({
// published. If you depend on uncompiled packages they may cause webpack build
// errors. To fix this webpack can be configured to compile to the necessary
// `node_module`.
//
// /\.tsx?$/ : process all tsx files.
// /.*@theoplayer\/.*\.js$/ : process all js files from @theoplayer packages to apply the root import alias. This is only needed for this example.
const babelLoaderConfiguration = {
test: /\.tsx?$/,
test: [/\.tsx?$/, /.*@theoplayer\/.*\.js$/],
exclude: ['/**/*.d.ts', '/**/node_modules/'],
use: {
loader: 'babel-loader',
options: {
cacheDirectory: true,
// The 'metro-react-native-babel-preset' preset is recommended to match React Native's packager
presets: ['module:metro-react-native-babel-preset'],
presets: ['module:@react-native/babel-preset'],
// Re-write paths to import only the modules needed by the app
plugins: ['react-native-web'],
},
Expand All @@ -68,15 +78,15 @@ const imageLoaderConfiguration = {
module.exports = {
entry: [
// load any web API polyfills
// path.resolve(projectDirectory, 'polyfills-web.js'),
// path.resolve(appDirectory, 'polyfills-web.js'),
// your web-specific entry file
path.resolve(projectDirectory, 'index.web.tsx'),
path.resolve(appDirectory, 'index.web.tsx'),
],

// configures where the build ends up
output: {
filename: 'bundle.web.js',
path: path.resolve(projectDirectory, outputLocation),
path: path.resolve(appDirectory, outputLocation),
},

module: {
Expand All @@ -88,22 +98,23 @@ module.exports = {
'react-native$': 'react-native-web',
'react-native-url-polyfill': 'url-polyfill',
'react-native-google-cast': path.resolve(stubDirectory, 'CastButtonStub'),
'react-native-web': path.resolve(projectDirectory, 'node_modules/react-native-web'),
'react-native-svg': path.resolve(projectDirectory, 'node_modules/react-native-svg-web'),
'react-native-web': path.resolve(appDirectory, 'node_modules/react-native-web'),
'react-native-svg': path.resolve(appDirectory, 'node_modules/react-native-svg-web'),
theoplayer: path.resolve(appDirectory, 'node_modules/theoplayer'),

// Avoid duplicate react env.
react: path.resolve(projectDirectory, 'node_modules/react'),
'react-dom': path.resolve(projectDirectory, 'node_modules/react-dom'),
react: path.resolve(appDirectory, 'node_modules/react'),
'react-dom': path.resolve(appDirectory, 'node_modules/react-dom'),
},
},
plugins: [HTMLWebpackPluginConfig, CopyWebpackPluginConfig, new NodePolyfillPlugin()],
plugins: [HTMLWebpackPluginConfig, CopyWebpackPluginConfig],
devServer: {
// Tells dev-server to open the browser after server had been started.
open: true,
historyApiFallback: true,
static: [
{
directory: path.join(projectDirectory, 'web/public'),
directory: path.join(appDirectory, 'web/public'),
},
],
// Hot reload on source changes
Expand Down
18 changes: 10 additions & 8 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@
},
"devDependencies": {
"@eslint/js": "^9.13.0",
"@react-native-community/slider": "^4.5.4",
"@react-native/eslint-config": "^0.75.4",
"@types/react": "^18.3.12",
"@typescript-eslint/eslint-plugin": "^7.18.0",
Expand All @@ -71,7 +70,6 @@
"typescript-eslint": "^8.11.0"
},
"peerDependencies": {
"@react-native-community/slider": "*",
"react": "*",
"react-native": "*",
"react-native-google-cast": "*",
Expand All @@ -97,6 +95,7 @@
]
},
"dependencies": {
"@miblanchard/react-native-slider": "^2.6.0",
"react-native-url-polyfill": "^1.3.0",
"url-polyfill": "^1.1.12"
}
Expand Down
8 changes: 0 additions & 8 deletions src/ui/components/button/PlayButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,18 +61,10 @@ export class PlayButton extends PureComponent<PlayButtonProps, PlayButtonState>
}

private onPlay = () => {
const player = (this.context as UiContext).player;
if (player.seeking) {
return;
}
this.setState({ paused: false, ended: false });
};

private onPause = () => {
const player = (this.context as UiContext).player;
if (player.seeking) {
return;
}
this.setState({ paused: true });
};

Expand Down
27 changes: 27 additions & 0 deletions src/ui/components/hooks/useCurrentTime.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { useCallback, useContext, useSyncExternalStore } from 'react';
import { PlayerContext } from '@theoplayer/react-native-ui';
import { type PlayerEventMap, PlayerEventType } from 'react-native-theoplayer';

const TIME_CHANGE_EVENTS = [PlayerEventType.TIME_UPDATE, PlayerEventType.SEEKING, PlayerEventType.SEEKED] satisfies ReadonlyArray<
keyof PlayerEventMap
>;

/**
* Returns {@link react-native-theoplayer!THEOplayer.duration | the player's current time}, automatically updating whenever it changes.
*
* This hook must only be used in a component mounted inside a {@link THEOplayerDefaultUi} or {@link UiContainer},
* or alternatively any other component that provides a {@link PlayerContext}.
*
* @group Hooks
*/
export const useCurrentTime = () => {
const { player } = useContext(PlayerContext);
const subscribe = useCallback(
(callback: () => void) => {
TIME_CHANGE_EVENTS.forEach((event) => player?.addEventListener(event, callback));
return () => TIME_CHANGE_EVENTS.forEach((event) => player?.removeEventListener(event, callback));
},
[player],
);
return useSyncExternalStore(subscribe, () => (player ? player.currentTime : 0));
};
Loading
Loading