react-native-tpstreams 1.1.3 → 1.1.4-dev.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -2
- package/TPStreamsRNPlayerView.podspec +1 -1
- package/android/app/build/generated/source/codegen/java/com/facebook/react/viewmanagers/TPStreamsRNPlayerViewManagerDelegate.java +87 -0
- package/android/app/build/generated/source/codegen/java/com/facebook/react/viewmanagers/TPStreamsRNPlayerViewManagerInterface.java +34 -0
- package/android/app/build/generated/source/codegen/jni/CMakeLists.txt +36 -0
- package/android/app/build/generated/source/codegen/jni/TPStreamsPlayerViewSpec-generated.cpp +22 -0
- package/android/app/build/generated/source/codegen/jni/TPStreamsPlayerViewSpec.h +24 -0
- package/android/app/build/generated/source/codegen/jni/react/renderer/components/TPStreamsPlayerViewSpec/ComponentDescriptors.cpp +22 -0
- package/android/app/build/generated/source/codegen/jni/react/renderer/components/TPStreamsPlayerViewSpec/ComponentDescriptors.h +24 -0
- package/android/app/build/generated/source/codegen/jni/react/renderer/components/TPStreamsPlayerViewSpec/EventEmitters.cpp +107 -0
- package/android/app/build/generated/source/codegen/jni/react/renderer/components/TPStreamsPlayerViewSpec/EventEmitters.h +81 -0
- package/android/app/build/generated/source/codegen/jni/react/renderer/components/TPStreamsPlayerViewSpec/Props.cpp +32 -0
- package/android/app/build/generated/source/codegen/jni/react/renderer/components/TPStreamsPlayerViewSpec/Props.h +34 -0
- package/android/app/build/generated/source/codegen/jni/react/renderer/components/TPStreamsPlayerViewSpec/ShadowNodes.cpp +17 -0
- package/android/app/build/generated/source/codegen/jni/react/renderer/components/TPStreamsPlayerViewSpec/ShadowNodes.h +32 -0
- package/android/app/build/generated/source/codegen/jni/react/renderer/components/TPStreamsPlayerViewSpec/States.cpp +16 -0
- package/android/app/build/generated/source/codegen/jni/react/renderer/components/TPStreamsPlayerViewSpec/States.h +29 -0
- package/android/app/build/generated/source/codegen/jni/react/renderer/components/TPStreamsPlayerViewSpec/TPStreamsPlayerViewSpecJSI-generated.cpp +17 -0
- package/android/app/build/generated/source/codegen/jni/react/renderer/components/TPStreamsPlayerViewSpec/TPStreamsPlayerViewSpecJSI.h +19 -0
- package/android/gradle.properties +1 -1
- package/android/src/main/java/com/tpstreams/TPStreamsRNPlayerView.kt +6 -0
- package/android/src/main/java/com/tpstreams/TPStreamsRNPlayerViewManager.kt +5 -0
- package/ios/TPStreamsRNPlayerView.swift +2 -0
- package/ios/TPStreamsRNPlayerViewManager.m +1 -0
- package/lib/module/TPStreamsLiveChat.js +133 -0
- package/lib/module/TPStreamsLiveChat.js.map +1 -0
- package/lib/module/TPStreamsPlayer.js +2 -0
- package/lib/module/TPStreamsPlayer.js.map +1 -1
- package/lib/module/TPStreamsPlayerViewNativeComponent.ts +1 -0
- package/lib/module/index.js +1 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/types/TPStreamsLiveChatTypes.js +29 -0
- package/lib/module/types/TPStreamsLiveChatTypes.js.map +1 -0
- package/lib/module/utils/constants.js +28 -0
- package/lib/module/utils/constants.js.map +1 -0
- package/lib/module/utils/liveChatHtmlGenerator.js +131 -0
- package/lib/module/utils/liveChatHtmlGenerator.js.map +1 -0
- package/lib/typescript/src/TPStreamsLiveChat.d.ts +5 -0
- package/lib/typescript/src/TPStreamsLiveChat.d.ts.map +1 -0
- package/lib/typescript/src/TPStreamsPlayer.d.ts +1 -0
- package/lib/typescript/src/TPStreamsPlayer.d.ts.map +1 -1
- package/lib/typescript/src/TPStreamsPlayerViewNativeComponent.d.ts +2 -0
- package/lib/typescript/src/TPStreamsPlayerViewNativeComponent.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +2 -0
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/types/TPStreamsLiveChatTypes.d.ts +77 -0
- package/lib/typescript/src/types/TPStreamsLiveChatTypes.d.ts.map +1 -0
- package/lib/typescript/src/utils/constants.d.ts +20 -0
- package/lib/typescript/src/utils/constants.d.ts.map +1 -0
- package/lib/typescript/src/utils/liveChatHtmlGenerator.d.ts +6 -0
- package/lib/typescript/src/utils/liveChatHtmlGenerator.d.ts.map +1 -0
- package/package.json +4 -1
- package/src/TPStreamsLiveChat.tsx +189 -0
- package/src/TPStreamsPlayer.tsx +3 -0
- package/src/TPStreamsPlayerViewNativeComponent.ts +1 -0
- package/src/index.tsx +9 -0
- package/src/types/TPStreamsLiveChatTypes.ts +99 -0
- package/src/utils/constants.ts +28 -0
- package/src/utils/liveChatHtmlGenerator.ts +142 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import type { ViewStyle } from 'react-native';
|
|
2
|
+
/**
|
|
3
|
+
* Color configuration for the chat interface
|
|
4
|
+
*/
|
|
5
|
+
export interface ChatColors {
|
|
6
|
+
/** Primary brand color (buttons, links, accents) */
|
|
7
|
+
primary?: string;
|
|
8
|
+
/** Chat background color */
|
|
9
|
+
background?: string;
|
|
10
|
+
/** Default text color */
|
|
11
|
+
text?: string;
|
|
12
|
+
/** Input field background color */
|
|
13
|
+
inputBackground?: string;
|
|
14
|
+
/** Border and divider color */
|
|
15
|
+
border?: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Chat message structure
|
|
19
|
+
*/
|
|
20
|
+
export interface ChatMessage {
|
|
21
|
+
id: string;
|
|
22
|
+
username: string;
|
|
23
|
+
message: string;
|
|
24
|
+
timestamp: number;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Type guard for ChatMessage
|
|
28
|
+
*/
|
|
29
|
+
export declare function isChatMessage(data: any): data is ChatMessage;
|
|
30
|
+
/**
|
|
31
|
+
* Typography configuration for the chat interface
|
|
32
|
+
*/
|
|
33
|
+
export interface ChatTypography {
|
|
34
|
+
/** Base font size in pixels */
|
|
35
|
+
fontSize?: number;
|
|
36
|
+
/** Font family (e.g., 'Inter, sans-serif') */
|
|
37
|
+
fontFamily?: string;
|
|
38
|
+
/** Font weight (e.g., '400', 'bold', 600) */
|
|
39
|
+
fontWeight?: string | number;
|
|
40
|
+
/** Line height multiplier */
|
|
41
|
+
lineHeight?: number;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Props for TPStreamsLiveChat component
|
|
45
|
+
*/
|
|
46
|
+
export interface TPStreamsLiveChatProps {
|
|
47
|
+
/** Username of the current user */
|
|
48
|
+
username: string;
|
|
49
|
+
/** Room ID for the chat (obtained from live stream details) */
|
|
50
|
+
roomId: string;
|
|
51
|
+
/** Title displayed in the chat header */
|
|
52
|
+
title: string;
|
|
53
|
+
/** Color scheme configuration */
|
|
54
|
+
colors?: ChatColors;
|
|
55
|
+
/** Typography configuration */
|
|
56
|
+
typography?: ChatTypography;
|
|
57
|
+
/** Custom CSS to inject (for advanced users) */
|
|
58
|
+
customCSS?: string;
|
|
59
|
+
/** Container style */
|
|
60
|
+
style?: ViewStyle;
|
|
61
|
+
/** Called when chat is successfully loaded and ready */
|
|
62
|
+
onChatReady?: () => void;
|
|
63
|
+
/** Called when an error occurs */
|
|
64
|
+
onChatError?: (error: string) => void;
|
|
65
|
+
/** Called when a new message is received */
|
|
66
|
+
onMessageReceived?: (message: ChatMessage) => void;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Ref methods exposed by TPStreamsLiveChat component
|
|
70
|
+
*/
|
|
71
|
+
export interface TPStreamsLiveChatRef {
|
|
72
|
+
/** Reload the chat interface */
|
|
73
|
+
reload: () => void;
|
|
74
|
+
/** Inject custom CSS dynamically */
|
|
75
|
+
injectCSS?: (css: string) => void;
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=TPStreamsLiveChatTypes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TPStreamsLiveChatTypes.d.ts","sourceRoot":"","sources":["../../../../src/types/TPStreamsLiveChatTypes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAE9C;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,oDAAoD;IACpD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,4BAA4B;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,yBAAyB;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,mCAAmC;IACnC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,+BAA+B;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,GAAG,GAAG,IAAI,IAAI,WAAW,CAQ5D;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,+BAA+B;IAC/B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,8CAA8C;IAC9C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,6CAA6C;IAC7C,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC7B,6BAA6B;IAC7B,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IAErC,mCAAmC;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,+DAA+D;IAC/D,MAAM,EAAE,MAAM,CAAC;IACf,yCAAyC;IACzC,KAAK,EAAE,MAAM,CAAC;IAGd,iCAAiC;IACjC,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,+BAA+B;IAC/B,UAAU,CAAC,EAAE,cAAc,CAAC;IAG5B,gDAAgD;IAChD,SAAS,CAAC,EAAE,MAAM,CAAC;IAGnB,sBAAsB;IACtB,KAAK,CAAC,EAAE,SAAS,CAAC;IAGlB,wDAAwD;IACxD,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IACzB,kCAAkC;IAClC,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,4CAA4C;IAC5C,iBAAiB,CAAC,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,IAAI,CAAC;CACpD;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,gCAAgC;IAChC,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,oCAAoC;IACpC,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CACnC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* URLs for the Live Chat SDK assets and base configuration
|
|
3
|
+
*/
|
|
4
|
+
export declare const CHAT_SDK_CONSTANTS: {
|
|
5
|
+
BASE_URL: string;
|
|
6
|
+
STYLES_URL: string;
|
|
7
|
+
SDK_SCRIPT_URL: string;
|
|
8
|
+
DEFAULT_PRIMARY_COLOR: string;
|
|
9
|
+
DEFAULT_BACKGROUND_COLOR: string;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Message types for communication between WebView and React Native
|
|
13
|
+
*/
|
|
14
|
+
export declare enum ChatMessageType {
|
|
15
|
+
READY = "ready",
|
|
16
|
+
ERROR = "error",
|
|
17
|
+
MESSAGE = "message",
|
|
18
|
+
DEBUG = "debug"
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../../src/utils/constants.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,eAAO,MAAM,kBAAkB;;;;;;CAc9B,CAAC;AAEF;;GAEG;AACH,oBAAY,eAAe;IACzB,KAAK,UAAU;IACf,KAAK,UAAU;IACf,OAAO,YAAY;IACnB,KAAK,UAAU;CAChB"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { TPStreamsLiveChatProps } from '../types/TPStreamsLiveChatTypes';
|
|
2
|
+
/**
|
|
3
|
+
* Generates the complete HTML content for the chat WebView
|
|
4
|
+
*/
|
|
5
|
+
export declare function generateChatHTML(props: TPStreamsLiveChatProps): string;
|
|
6
|
+
//# sourceMappingURL=liveChatHtmlGenerator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"liveChatHtmlGenerator.d.ts","sourceRoot":"","sources":["../../../../src/utils/liveChatHtmlGenerator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,sBAAsB,EAGvB,MAAM,iCAAiC,CAAC;AAGzC;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,sBAAsB,GAAG,MAAM,CAyCtE"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-tpstreams",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.4-dev.1",
|
|
4
4
|
"description": "Video component for TPStreams",
|
|
5
5
|
"main": "./lib/module/index.js",
|
|
6
6
|
"types": "./lib/typescript/src/index.d.ts",
|
|
@@ -85,6 +85,9 @@
|
|
|
85
85
|
"turbo": "^1.10.7",
|
|
86
86
|
"typescript": "5.4.5"
|
|
87
87
|
},
|
|
88
|
+
"dependencies": {
|
|
89
|
+
"react-native-webview": "^13.16.0"
|
|
90
|
+
},
|
|
88
91
|
"peerDependencies": {
|
|
89
92
|
"react": "*",
|
|
90
93
|
"react-native": "*"
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import {
|
|
2
|
+
forwardRef,
|
|
3
|
+
useRef,
|
|
4
|
+
useImperativeHandle,
|
|
5
|
+
useState,
|
|
6
|
+
useCallback,
|
|
7
|
+
useMemo,
|
|
8
|
+
} from 'react';
|
|
9
|
+
import {
|
|
10
|
+
View,
|
|
11
|
+
ActivityIndicator,
|
|
12
|
+
StyleSheet,
|
|
13
|
+
type NativeSyntheticEvent,
|
|
14
|
+
} from 'react-native';
|
|
15
|
+
import { WebView, type WebViewMessageEvent } from 'react-native-webview';
|
|
16
|
+
|
|
17
|
+
import type {
|
|
18
|
+
TPStreamsLiveChatProps,
|
|
19
|
+
TPStreamsLiveChatRef,
|
|
20
|
+
} from './types/TPStreamsLiveChatTypes';
|
|
21
|
+
import { isChatMessage } from './types/TPStreamsLiveChatTypes';
|
|
22
|
+
import { generateChatHTML } from './utils/liveChatHtmlGenerator';
|
|
23
|
+
import { CHAT_SDK_CONSTANTS, ChatMessageType } from './utils/constants';
|
|
24
|
+
|
|
25
|
+
const TPStreamsLiveChat = forwardRef<
|
|
26
|
+
TPStreamsLiveChatRef,
|
|
27
|
+
TPStreamsLiveChatProps
|
|
28
|
+
>((props, ref) => {
|
|
29
|
+
const {
|
|
30
|
+
username,
|
|
31
|
+
roomId,
|
|
32
|
+
title,
|
|
33
|
+
colors,
|
|
34
|
+
typography,
|
|
35
|
+
customCSS,
|
|
36
|
+
style,
|
|
37
|
+
onChatReady,
|
|
38
|
+
onChatError,
|
|
39
|
+
onMessageReceived,
|
|
40
|
+
} = props;
|
|
41
|
+
|
|
42
|
+
const webViewRef = useRef<WebView>(null);
|
|
43
|
+
const [status, setStatus] = useState<'loading' | 'ready' | 'error'>(
|
|
44
|
+
'loading'
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
const htmlContent = useMemo(
|
|
48
|
+
() =>
|
|
49
|
+
generateChatHTML({
|
|
50
|
+
username,
|
|
51
|
+
roomId,
|
|
52
|
+
title,
|
|
53
|
+
colors,
|
|
54
|
+
typography,
|
|
55
|
+
customCSS,
|
|
56
|
+
}),
|
|
57
|
+
[username, roomId, title, colors, typography, customCSS]
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
const handleMessage = useCallback(
|
|
61
|
+
(event: WebViewMessageEvent) => {
|
|
62
|
+
try {
|
|
63
|
+
const { type, message } = JSON.parse(event.nativeEvent.data);
|
|
64
|
+
|
|
65
|
+
switch (type) {
|
|
66
|
+
case ChatMessageType.READY:
|
|
67
|
+
setStatus('ready');
|
|
68
|
+
onChatReady?.();
|
|
69
|
+
break;
|
|
70
|
+
|
|
71
|
+
case ChatMessageType.ERROR:
|
|
72
|
+
setStatus('error');
|
|
73
|
+
onChatError?.(message || 'SDK initialization failed');
|
|
74
|
+
break;
|
|
75
|
+
|
|
76
|
+
case ChatMessageType.MESSAGE:
|
|
77
|
+
if (isChatMessage(message)) {
|
|
78
|
+
onMessageReceived?.(message);
|
|
79
|
+
} else {
|
|
80
|
+
console.warn(
|
|
81
|
+
'[TPStreamsLiveChat] Received invalid message format:',
|
|
82
|
+
message
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
break;
|
|
86
|
+
|
|
87
|
+
case ChatMessageType.DEBUG:
|
|
88
|
+
console.debug('[TPStreamsLiveChat] WebView:', message);
|
|
89
|
+
break;
|
|
90
|
+
}
|
|
91
|
+
} catch (err) {
|
|
92
|
+
console.error('[TPStreamsLiveChat] Failed to parse message:', err);
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
[onChatReady, onChatError, onMessageReceived]
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
const handleWebViewError = useCallback(
|
|
99
|
+
(syntheticEvent: NativeSyntheticEvent<any>) => {
|
|
100
|
+
const { nativeEvent } = syntheticEvent;
|
|
101
|
+
setStatus('error');
|
|
102
|
+
onChatError?.(nativeEvent.description || 'WebView failed to load');
|
|
103
|
+
},
|
|
104
|
+
[onChatError]
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
useImperativeHandle(
|
|
108
|
+
ref,
|
|
109
|
+
() => ({
|
|
110
|
+
reload: () => {
|
|
111
|
+
setStatus('loading');
|
|
112
|
+
webViewRef.current?.reload();
|
|
113
|
+
},
|
|
114
|
+
injectCSS: (css: string) => {
|
|
115
|
+
const script = `
|
|
116
|
+
(function() {
|
|
117
|
+
const style = document.createElement('style');
|
|
118
|
+
style.textContent = ${JSON.stringify(css)};
|
|
119
|
+
document.head.appendChild(style);
|
|
120
|
+
})();
|
|
121
|
+
`;
|
|
122
|
+
webViewRef.current?.injectJavaScript(script);
|
|
123
|
+
},
|
|
124
|
+
}),
|
|
125
|
+
[]
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
const renderLoading = () =>
|
|
129
|
+
status === 'loading' && (
|
|
130
|
+
<View
|
|
131
|
+
style={[
|
|
132
|
+
styles.overlay,
|
|
133
|
+
{
|
|
134
|
+
backgroundColor:
|
|
135
|
+
colors?.background || CHAT_SDK_CONSTANTS.DEFAULT_BACKGROUND_COLOR,
|
|
136
|
+
},
|
|
137
|
+
]}
|
|
138
|
+
>
|
|
139
|
+
<ActivityIndicator
|
|
140
|
+
size="large"
|
|
141
|
+
color={colors?.primary || CHAT_SDK_CONSTANTS.DEFAULT_PRIMARY_COLOR}
|
|
142
|
+
/>
|
|
143
|
+
</View>
|
|
144
|
+
);
|
|
145
|
+
|
|
146
|
+
return (
|
|
147
|
+
<View style={[styles.container, style]}>
|
|
148
|
+
<WebView
|
|
149
|
+
key={`${colors?.background}-${typography?.fontFamily}`}
|
|
150
|
+
ref={webViewRef}
|
|
151
|
+
source={{
|
|
152
|
+
html: htmlContent,
|
|
153
|
+
baseUrl: CHAT_SDK_CONSTANTS.BASE_URL,
|
|
154
|
+
}}
|
|
155
|
+
originWhitelist={[CHAT_SDK_CONSTANTS.BASE_URL]}
|
|
156
|
+
javaScriptEnabled={true}
|
|
157
|
+
domStorageEnabled={true}
|
|
158
|
+
onMessage={handleMessage}
|
|
159
|
+
onError={handleWebViewError}
|
|
160
|
+
style={styles.webview}
|
|
161
|
+
allowsInlineMediaPlayback={true}
|
|
162
|
+
mediaPlaybackRequiresUserAction={false}
|
|
163
|
+
scrollEnabled={false}
|
|
164
|
+
/>
|
|
165
|
+
{renderLoading()}
|
|
166
|
+
</View>
|
|
167
|
+
);
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
TPStreamsLiveChat.displayName = 'TPStreamsLiveChat';
|
|
171
|
+
|
|
172
|
+
const styles = StyleSheet.create({
|
|
173
|
+
container: {
|
|
174
|
+
flex: 1,
|
|
175
|
+
overflow: 'hidden',
|
|
176
|
+
},
|
|
177
|
+
webview: {
|
|
178
|
+
flex: 1,
|
|
179
|
+
backgroundColor: 'transparent',
|
|
180
|
+
},
|
|
181
|
+
overlay: {
|
|
182
|
+
...StyleSheet.absoluteFillObject,
|
|
183
|
+
justifyContent: 'center',
|
|
184
|
+
alignItems: 'center',
|
|
185
|
+
zIndex: 10,
|
|
186
|
+
},
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
export default TPStreamsLiveChat;
|
package/src/TPStreamsPlayer.tsx
CHANGED
|
@@ -40,6 +40,7 @@ export interface TPStreamsPlayerProps extends ViewProps {
|
|
|
40
40
|
enableDownload?: boolean;
|
|
41
41
|
offlineLicenseExpireTime?: number;
|
|
42
42
|
showDefaultCaptions?: boolean;
|
|
43
|
+
startInFullscreen?: boolean;
|
|
43
44
|
downloadMetadata?: { [key: string]: any };
|
|
44
45
|
onPlayerStateChanged?: (state: number) => void;
|
|
45
46
|
onIsPlayingChanged?: (isPlaying: boolean) => void;
|
|
@@ -72,6 +73,7 @@ const TPStreamsPlayerView = forwardRef<
|
|
|
72
73
|
enableDownload,
|
|
73
74
|
offlineLicenseExpireTime,
|
|
74
75
|
showDefaultCaptions,
|
|
76
|
+
startInFullscreen,
|
|
75
77
|
downloadMetadata,
|
|
76
78
|
style,
|
|
77
79
|
onPlayerStateChanged,
|
|
@@ -243,6 +245,7 @@ const TPStreamsPlayerView = forwardRef<
|
|
|
243
245
|
startAt,
|
|
244
246
|
enableDownload,
|
|
245
247
|
showDefaultCaptions,
|
|
248
|
+
startInFullscreen,
|
|
246
249
|
downloadMetadata: downloadMetadata
|
|
247
250
|
? JSON.stringify(downloadMetadata)
|
|
248
251
|
: undefined,
|
|
@@ -23,6 +23,7 @@ export interface NativeProps extends ViewProps {
|
|
|
23
23
|
enableDownload?: boolean;
|
|
24
24
|
offlineLicenseExpireTime?: Double;
|
|
25
25
|
showDefaultCaptions?: boolean;
|
|
26
|
+
startInFullscreen?: boolean;
|
|
26
27
|
downloadMetadata?: string;
|
|
27
28
|
|
|
28
29
|
// Event props for receiving data from native methods
|
package/src/index.tsx
CHANGED
|
@@ -33,3 +33,12 @@ export const TPStreams = {
|
|
|
33
33
|
TPStreamsModule.initialize(organizationId);
|
|
34
34
|
},
|
|
35
35
|
};
|
|
36
|
+
|
|
37
|
+
export { default as TPStreamsLiveChat } from './TPStreamsLiveChat';
|
|
38
|
+
export type {
|
|
39
|
+
TPStreamsLiveChatProps,
|
|
40
|
+
TPStreamsLiveChatRef,
|
|
41
|
+
ChatColors,
|
|
42
|
+
ChatTypography,
|
|
43
|
+
ChatMessage,
|
|
44
|
+
} from './types/TPStreamsLiveChatTypes';
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import type { ViewStyle } from 'react-native';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Color configuration for the chat interface
|
|
5
|
+
*/
|
|
6
|
+
export interface ChatColors {
|
|
7
|
+
/** Primary brand color (buttons, links, accents) */
|
|
8
|
+
primary?: string;
|
|
9
|
+
/** Chat background color */
|
|
10
|
+
background?: string;
|
|
11
|
+
/** Default text color */
|
|
12
|
+
text?: string;
|
|
13
|
+
/** Input field background color */
|
|
14
|
+
inputBackground?: string;
|
|
15
|
+
/** Border and divider color */
|
|
16
|
+
border?: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Chat message structure
|
|
21
|
+
*/
|
|
22
|
+
export interface ChatMessage {
|
|
23
|
+
id: string;
|
|
24
|
+
username: string;
|
|
25
|
+
message: string;
|
|
26
|
+
timestamp: number;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Type guard for ChatMessage
|
|
31
|
+
*/
|
|
32
|
+
export function isChatMessage(data: any): data is ChatMessage {
|
|
33
|
+
return (
|
|
34
|
+
data &&
|
|
35
|
+
typeof data.id === 'string' &&
|
|
36
|
+
typeof data.username === 'string' &&
|
|
37
|
+
typeof data.message === 'string' &&
|
|
38
|
+
typeof data.timestamp === 'number'
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Typography configuration for the chat interface
|
|
44
|
+
*/
|
|
45
|
+
export interface ChatTypography {
|
|
46
|
+
/** Base font size in pixels */
|
|
47
|
+
fontSize?: number;
|
|
48
|
+
/** Font family (e.g., 'Inter, sans-serif') */
|
|
49
|
+
fontFamily?: string;
|
|
50
|
+
/** Font weight (e.g., '400', 'bold', 600) */
|
|
51
|
+
fontWeight?: string | number;
|
|
52
|
+
/** Line height multiplier */
|
|
53
|
+
lineHeight?: number;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Props for TPStreamsLiveChat component
|
|
58
|
+
*/
|
|
59
|
+
export interface TPStreamsLiveChatProps {
|
|
60
|
+
// Required configuration
|
|
61
|
+
/** Username of the current user */
|
|
62
|
+
username: string;
|
|
63
|
+
/** Room ID for the chat (obtained from live stream details) */
|
|
64
|
+
roomId: string;
|
|
65
|
+
/** Title displayed in the chat header */
|
|
66
|
+
title: string;
|
|
67
|
+
|
|
68
|
+
// Optional styling configuration
|
|
69
|
+
/** Color scheme configuration */
|
|
70
|
+
colors?: ChatColors;
|
|
71
|
+
/** Typography configuration */
|
|
72
|
+
typography?: ChatTypography;
|
|
73
|
+
|
|
74
|
+
// Advanced customization
|
|
75
|
+
/** Custom CSS to inject (for advanced users) */
|
|
76
|
+
customCSS?: string;
|
|
77
|
+
|
|
78
|
+
// Standard React Native props
|
|
79
|
+
/** Container style */
|
|
80
|
+
style?: ViewStyle;
|
|
81
|
+
|
|
82
|
+
// Event callbacks
|
|
83
|
+
/** Called when chat is successfully loaded and ready */
|
|
84
|
+
onChatReady?: () => void;
|
|
85
|
+
/** Called when an error occurs */
|
|
86
|
+
onChatError?: (error: string) => void;
|
|
87
|
+
/** Called when a new message is received */
|
|
88
|
+
onMessageReceived?: (message: ChatMessage) => void;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Ref methods exposed by TPStreamsLiveChat component
|
|
93
|
+
*/
|
|
94
|
+
export interface TPStreamsLiveChatRef {
|
|
95
|
+
/** Reload the chat interface */
|
|
96
|
+
reload: () => void;
|
|
97
|
+
/** Inject custom CSS dynamically */
|
|
98
|
+
injectCSS?: (css: string) => void;
|
|
99
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* URLs for the Live Chat SDK assets and base configuration
|
|
3
|
+
*/
|
|
4
|
+
export const CHAT_SDK_CONSTANTS = {
|
|
5
|
+
// The domain where the chat is hosted/associated
|
|
6
|
+
BASE_URL: 'https://media.testpress.in',
|
|
7
|
+
|
|
8
|
+
// CDN path for the CSS styles
|
|
9
|
+
STYLES_URL: 'https://media.testpress.in/static/live_chat/live_chat.css',
|
|
10
|
+
|
|
11
|
+
// CDN path for the UMD build of the SDK
|
|
12
|
+
SDK_SCRIPT_URL:
|
|
13
|
+
'https://media.testpress.in/static/live_chat/live_chat.umd.cjs',
|
|
14
|
+
|
|
15
|
+
// Default values
|
|
16
|
+
DEFAULT_PRIMARY_COLOR: '#007AFF',
|
|
17
|
+
DEFAULT_BACKGROUND_COLOR: '#FFFFFF',
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Message types for communication between WebView and React Native
|
|
22
|
+
*/
|
|
23
|
+
export enum ChatMessageType {
|
|
24
|
+
READY = 'ready',
|
|
25
|
+
ERROR = 'error',
|
|
26
|
+
MESSAGE = 'message',
|
|
27
|
+
DEBUG = 'debug',
|
|
28
|
+
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
TPStreamsLiveChatProps,
|
|
3
|
+
ChatColors,
|
|
4
|
+
ChatTypography,
|
|
5
|
+
} from '../types/TPStreamsLiveChatTypes';
|
|
6
|
+
import { CHAT_SDK_CONSTANTS, ChatMessageType } from './constants';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Generates the complete HTML content for the chat WebView
|
|
10
|
+
*/
|
|
11
|
+
export function generateChatHTML(props: TPStreamsLiveChatProps): string {
|
|
12
|
+
const { username, roomId, title } = props;
|
|
13
|
+
const styles = generateStylesAndScripts(props);
|
|
14
|
+
|
|
15
|
+
return `
|
|
16
|
+
<!DOCTYPE html>
|
|
17
|
+
<html lang="en" style="height: 100%; margin: 0;">
|
|
18
|
+
<head>
|
|
19
|
+
<meta charset="UTF-8">
|
|
20
|
+
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
|
|
21
|
+
<link rel="stylesheet" href="${CHAT_SDK_CONSTANTS.STYLES_URL}">
|
|
22
|
+
${styles.css}
|
|
23
|
+
</head>
|
|
24
|
+
<body style="height: 100%; margin: 0; overflow: hidden;">
|
|
25
|
+
<div id="app" style="height: 100%;"></div>
|
|
26
|
+
<script src="${CHAT_SDK_CONSTANTS.SDK_SCRIPT_URL}"></script>
|
|
27
|
+
<script>
|
|
28
|
+
(function() {
|
|
29
|
+
const config = {
|
|
30
|
+
username: ${JSON.stringify(username)},
|
|
31
|
+
roomId: ${JSON.stringify(roomId)},
|
|
32
|
+
title: ${JSON.stringify(title)}
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
function postToNative(type, message = null) {
|
|
36
|
+
if (window.ReactNativeWebView) {
|
|
37
|
+
window.ReactNativeWebView.postMessage(JSON.stringify({ type, message }));
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
try {
|
|
42
|
+
new TPStreamsChat.load(document.querySelector("#app"), config);
|
|
43
|
+
postToNative('${ChatMessageType.READY}');
|
|
44
|
+
} catch (error) {
|
|
45
|
+
postToNative('${ChatMessageType.ERROR}', error.message || 'Failed to initialize chat');
|
|
46
|
+
}
|
|
47
|
+
})();
|
|
48
|
+
</script>
|
|
49
|
+
</body>
|
|
50
|
+
</html>
|
|
51
|
+
`;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Combines all CSS generation logic
|
|
56
|
+
*/
|
|
57
|
+
function generateStylesAndScripts(props: TPStreamsLiveChatProps) {
|
|
58
|
+
const { colors, typography, customCSS } = props;
|
|
59
|
+
const rules: string[] = [];
|
|
60
|
+
|
|
61
|
+
if (typography) rules.push(getTypographyCSS(typography));
|
|
62
|
+
if (colors) rules.push(getColorCSS(colors));
|
|
63
|
+
if (customCSS) rules.push(customCSS);
|
|
64
|
+
|
|
65
|
+
return {
|
|
66
|
+
css: `<style>${rules.join('\n\n')}</style>`,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Generate color-related CSS using functional approach
|
|
72
|
+
*/
|
|
73
|
+
function getColorCSS(colors: ChatColors): string {
|
|
74
|
+
const rules: string[] = [];
|
|
75
|
+
|
|
76
|
+
if (colors.primary) {
|
|
77
|
+
rules.push(`
|
|
78
|
+
button, [class*="bg-blue-"], [class*="bg-indigo-"], [class*="primary"] {
|
|
79
|
+
background-color: ${colors.primary} !important;
|
|
80
|
+
color: white !important;
|
|
81
|
+
}
|
|
82
|
+
.text-blue-600, .text-indigo-600, [class*="text-blue-"]:not([class*="bg-"]), [class*="text-indigo-"]:not([class*="bg-"]) {
|
|
83
|
+
color: ${colors.primary} !important;
|
|
84
|
+
}
|
|
85
|
+
[class*="bg-blue-"] *, [class*="bg-indigo-"] *, [class*="primary"] * {
|
|
86
|
+
color: white !important;
|
|
87
|
+
}
|
|
88
|
+
`);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (colors.background) {
|
|
92
|
+
rules.push(`
|
|
93
|
+
body, #app, .chat-container, [class*="bg-white"], [class*="bg-gray-50"], [class*="bg-slate-"] {
|
|
94
|
+
background-color: ${colors.background} !important;
|
|
95
|
+
}
|
|
96
|
+
`);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (colors.text) {
|
|
100
|
+
rules.push(`
|
|
101
|
+
body, p, input, textarea,
|
|
102
|
+
div:not([class*="bg-blue-"]):not([class*="bg-indigo-"]):not([class*="primary"]),
|
|
103
|
+
span:not([class*="bg-blue-"]):not([class*="bg-indigo-"]):not([class*="primary"]) {
|
|
104
|
+
color: ${colors.text} !important;
|
|
105
|
+
}
|
|
106
|
+
`);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (colors.inputBackground) {
|
|
110
|
+
rules.push(`
|
|
111
|
+
textarea, input[type="text"], [class*="bg-gray-"], [class*="bg-slate-"] {
|
|
112
|
+
background-color: ${colors.inputBackground} !important;
|
|
113
|
+
}
|
|
114
|
+
`);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (colors.border) {
|
|
118
|
+
rules.push(`
|
|
119
|
+
[class*="border"], [class*="divide-"] > * {
|
|
120
|
+
border-color: ${colors.border} !important;
|
|
121
|
+
}
|
|
122
|
+
`);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return rules.join('\n');
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function getTypographyCSS(typography: ChatTypography): string {
|
|
129
|
+
const styles: string[] = [];
|
|
130
|
+
if (typography.fontSize)
|
|
131
|
+
styles.push(`font-size: ${typography.fontSize}px !important;`);
|
|
132
|
+
if (typography.fontFamily)
|
|
133
|
+
styles.push(`font-family: ${typography.fontFamily} !important;`);
|
|
134
|
+
if (typography.fontWeight)
|
|
135
|
+
styles.push(`font-weight: ${typography.fontWeight} !important;`);
|
|
136
|
+
if (typography.lineHeight)
|
|
137
|
+
styles.push(`line-height: ${typography.lineHeight} !important;`);
|
|
138
|
+
|
|
139
|
+
return styles.length > 0
|
|
140
|
+
? `body, button, input, textarea, div, span, p { ${styles.join(' ')} }`
|
|
141
|
+
: '';
|
|
142
|
+
}
|