diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..a6ae739
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,20 @@
+# .github/workflows/ci.yml
+name: CI – Cloudinary React Native SDK
+
+on: [push, pull_request]
+
+jobs:
+ test:
+ runs-on: ubuntu-22.04
+
+ steps:
+ - uses: actions/checkout@v3
+
+ - uses: actions/setup-node@v3
+ with:
+ node-version: 18
+ cache: npm
+
+ - run: npm ci
+ - run: npm run prepack
+ - run: npm test
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index fbbd405..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,13 +0,0 @@
-language: node_js
-before_script:
- - npm install
-before_install:
- - npm run
-script:
- - npm test
-after_success:
- - coverage
-notifications:
- email:
- recipients:
- - sdk_developers@cloudinary.com
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a639be5..2d697ef 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,18 @@
+1.1.0 / 2025-22-06
+==================
+
+* Add video player analytics
+
+1.0.2 / 2025-18-06
+==================
+
+* Fix API parameters signature
+
+1.0.1 / 2024-30-09
+==================
+
+* Bump dependencies
+
1.0.0 / 2024-19-05
==================
diff --git a/README.md b/README.md
index 0da732b..90034ba 100644
--- a/README.md
+++ b/README.md
@@ -23,7 +23,7 @@ Transform and optimize assets. Visit our documentation to learn more about [medi
## Version Support
| SDK Version | React Native Version |
|-------------|----------------------|
-| 1.0.0 | > 0.6 |
+| 1.x.x | > 0.6 |
## Installation
### Install using your favorite package manager (yarn, npm)
@@ -36,6 +36,17 @@ Or
yarn add cloudinary-react-native --save
```
+### For Video Player functionality
+If you want to use the video player features, you need to install `expo-av`:
+
+```bash
+npm install expo-av
+```
+Or
+```bash
+yarn add expo-av
+```
+
## Usage
### Setup
The `Cloudinary` class is the main entry point for using the library. Your `cloud_name` is required to create an instance of this class. Your `api_key` and `api_secret` are also needed to perform secure API calls to Cloudinary (e.g., image and video uploads). Setting the configuration parameters can be done either programmatically using an appropriate constructor of the Cloudinary class or globally using an environment variable. You can find your account-specific configuration parameters in the **Dashboard** page of your [account console](https://cloudinary.com/console).
@@ -71,6 +82,70 @@ export default function App() {
};
```
+### Video Player
+The `AdvancedVideo` component provides video playback capabilities with optional analytics tracking. **Note: This requires `expo-av` to be installed.**
+
+```tsx
+import { AdvancedVideo } from 'cloudinary-react-native';
+import {Cloudinary} from '@cloudinary/url-gen';
+
+const myCld = new Cloudinary({
+ cloud: {
+ cloudName: "demo",
+ },
+});
+
+let video = myCld.video('sea_turtle');
+
+export default function App() {
+ return (
+
+
+
+ );
+};
+```
+
+#### Video Player with Analytics
+Enable analytics tracking for detailed video performance insights:
+
+```tsx
+import { AdvancedVideo } from 'cloudinary-react-native';
+import {Cloudinary} from '@cloudinary/url-gen';
+
+const myCld = new Cloudinary({
+ cloud: {
+ cloudName: "demo",
+ },
+});
+
+let video = myCld.video('sea_turtle');
+
+export default function App() {
+ return (
+
+
+
+ );
+};
+```
+
### Uploading Assets
The following example performs an unsigned upload of a `string` using the default settings, a request upload callback, and an upload preset (required for unsigned uploads):
diff --git a/__mocks__/cloudinary-video-analytics.ts b/__mocks__/cloudinary-video-analytics.ts
new file mode 100644
index 0000000..293ac37
--- /dev/null
+++ b/__mocks__/cloudinary-video-analytics.ts
@@ -0,0 +1,14 @@
+export const videoStarted = jest.fn();
+export const videoPlayed = jest.fn();
+export const videoPaused = jest.fn();
+export const videoCompleted = jest.fn();
+export const updateVideoDuration = jest.fn();
+
+export const CloudinaryVideoAnalytics = jest.fn().mockImplementation((config: any) => ({
+ config,
+ videoStarted,
+ videoPlayed,
+ videoPaused,
+ videoCompleted,
+ updateVideoDuration,
+}));
diff --git a/example/App.tsx b/example/App.tsx
index f274696..2f696be 100644
--- a/example/App.tsx
+++ b/example/App.tsx
@@ -1,13 +1,25 @@
-import { StyleSheet, View } from 'react-native';
+import { StyleSheet, View, Text, TouchableOpacity, Alert, Platform, Dimensions } from 'react-native';
+import { StatusBar } from 'expo-status-bar';
import {AdvancedImage, AdvancedVideo} from 'cloudinary-react-native';
import {Cloudinary} from '@cloudinary/url-gen';
import {scale} from "@cloudinary/url-gen/actions/resize";
import {cartoonify} from "@cloudinary/url-gen/actions/effect";
import {max} from "@cloudinary/url-gen/actions/roundCorners";
-import React, {useRef} from "react";
-import { streamingProfile } from '@cloudinary/url-gen/actions/transcode';
-import { Video } from 'expo-av';
-import { } from 'cloudinary-react-native';
+import React, {useRef, useState} from "react";
+
+const { height: screenHeight, width: screenWidth } = Dimensions.get('window');
+
+// Calculate safe area padding based on screen dimensions
+const getTopPadding = () => {
+ if (Platform.OS === 'ios') {
+ // For iPhone X and newer (with notch), screen height is typically 812+ or width 390+
+ if (screenHeight >= 812 || screenWidth >= 390) {
+ return 60; // Devices with notch
+ }
+ return 40; // Older devices
+ }
+ return 35; // Android
+};
const cld = new Cloudinary({
cloud: {
@@ -17,40 +29,212 @@ const cld = new Cloudinary({
secure: true
}
});
+
export default function App() {
+ const videoPlayer = useRef(null);
+ const [analyticsEnabled, setAnalyticsEnabled] = useState(false);
+ const [autoTracking, setAutoTracking] = useState(false);
- const videoPlayer = useRef