diff --git a/frontend/app/components/Session/Player/MobilePlayer/PlayerInst.tsx b/frontend/app/components/Session/Player/MobilePlayer/PlayerInst.tsx index 4ee3347dc..188f286ef 100644 --- a/frontend/app/components/Session/Player/MobilePlayer/PlayerInst.tsx +++ b/frontend/app/components/Session/Player/MobilePlayer/PlayerInst.tsx @@ -41,6 +41,9 @@ interface IProps { videoURL: string[]; setActiveTab: (tab: string) => void; userDevice: string; + screenWidth: number; + screenHeight: number; + platform: string; } function Player(props: IProps) { @@ -55,6 +58,9 @@ function Player(props: IProps) { fullView, videoURL, userDevice, + screenWidth, + screenHeight, + platform, } = props; const playerContext = React.useContext(MobilePlayerContext); const isReady = playerContext.store.get().ready @@ -106,6 +112,7 @@ function Player(props: IProps) { document.addEventListener('mouseup', handleMouseUp); }; + const isAndroid = platform === 'android'; return (
- +
@@ -162,6 +175,9 @@ export default connect( userDevice: state.getIn(['sessions', 'current']).userDevice, videoURL: state.getIn(['sessions', 'current']).videoURL, bottomBlock: state.getIn(['components', 'player', 'bottomBlock']), + platform: state.getIn(['sessions', 'current']).platform, + screenWidth: state.getIn(['sessions', 'current']).screenWidth, + screenHeight: state.getIn(['sessions', 'current']).screenHeight, }), { fullscreenOff, diff --git a/frontend/app/components/Session/Player/MobilePlayer/ReplayWindow.tsx b/frontend/app/components/Session/Player/MobilePlayer/ReplayWindow.tsx index 0394a3d34..64a08bb49 100644 --- a/frontend/app/components/Session/Player/MobilePlayer/ReplayWindow.tsx +++ b/frontend/app/components/Session/Player/MobilePlayer/ReplayWindow.tsx @@ -2,11 +2,14 @@ import { PlayerMode } from 'Player'; import React from 'react'; import { MobilePlayerContext, IOSPlayerContext } from 'App/components/Session/playerContext'; import { observer } from 'mobx-react-lite'; -import { mapIphoneModel } from 'Player/mobile/utils'; +import { mapIphoneModel, mapAndroidModel } from 'Player/mobile/utils'; interface Props { videoURL: string[]; userDevice: string; + isAndroid: boolean; + screenWidth: number; + screenHeight: number; } const appleIcon = ` @@ -14,13 +17,25 @@ const appleIcon = ` `; -function ReplayWindow({ videoURL, userDevice }: Props) { +function ReplayWindow({ videoURL, userDevice, screenHeight, screenWidth, isAndroid }: Props) { const playerContext = React.useContext(MobilePlayerContext); const videoRef = React.useRef(); const imageRef = React.useRef(); const containerRef = React.useRef(); const { time, currentSnapshot, mode } = playerContext.store.get(); + // TODO: add android styles + let phoneShell: string; + let styles: Record; + if (!isAndroid) { + const { svg: iphoneShellSvg, styles: iphoneStyles } = mapIphoneModel(userDevice); + phoneShell = iphoneShellSvg + styles = iphoneStyles + } else { + const { svg: androidShell, styles: androidStyles } = mapAndroidModel(screenWidth, screenHeight) + phoneShell = androidShell + styles = androidStyles + } React.useEffect(() => { if (videoRef.current && mode === PlayerMode.VIDEO) { @@ -45,9 +60,9 @@ function ReplayWindow({ videoURL, userDevice }: Props) { } }, [currentSnapshot, mode]); + React.useEffect(() => { playerContext.player.pause() - const { svg, styles } = mapIphoneModel(userDevice); if (!containerRef.current && playerContext.player.screen.document) { const host = document.createElement('div'); const shell = document.createElement('div'); @@ -61,7 +76,7 @@ function ReplayWindow({ videoURL, userDevice }: Props) { videoContainer.style.width = styles.screen.width + 'px'; videoContainer.style.height = styles.screen.height + 'px'; - shell.innerHTML = svg; + shell.innerHTML = phoneShell; Object.assign(icon.style, mobileIconStyle(styles)); const spacer = document.createElement('div'); spacer.style.width = '60px'; @@ -70,6 +85,7 @@ function ReplayWindow({ videoURL, userDevice }: Props) { const loadingBar = document.createElement('div'); Object.assign(loadingBar.style, mobileLoadingBarStyle(styles)); + // TODO: add android icon.innerHTML = appleIcon; shell.style.position = 'absolute'; @@ -84,8 +100,8 @@ function ReplayWindow({ videoURL, userDevice }: Props) { containerRef.current = host; videoContainer.id = '___or_replay-video'; - icon.id = '___or_ios-icon'; - host.id = '___or_ios-player'; + icon.id = '___or_mobile-loader-icon'; + host.id = '___or_mobile-player'; playerContext.player.injectPlayer(host); playerContext.player.customScale(styles.shell.width, styles.shell.height); @@ -102,12 +118,11 @@ function ReplayWindow({ videoURL, userDevice }: Props) { }, [playerContext.player.screen.document]); React.useEffect(() => { - const { styles } = mapIphoneModel(userDevice); if (mode) { const host = containerRef.current; const videoContainer = playerContext.player.screen.document?.getElementById('___or_replay-video'); - const icon = playerContext.player.screen.document?.getElementById('___or_ios-icon'); + const icon = playerContext.player.screen.document?.getElementById('___or_mobile-loader-icon'); if (host && videoContainer && icon) { if (mode === PlayerMode.SNAPS) { const imagePlayer = document.createElement('img'); @@ -156,6 +171,11 @@ function ReplayWindow({ videoURL, userDevice }: Props) { return
; } +const getAndroidShell = ({ width, height }: { width: number; height: number }): string => `
+
+
+
`; + const mobileLoadingBarStyle = (styles: any) => ({ width: styles.screen.width / 2 + 'px', height: '6px', diff --git a/frontend/app/player/mobile/utils.ts b/frontend/app/player/mobile/utils.ts index 1e434d466..0b9b4995e 100644 --- a/frontend/app/player/mobile/utils.ts +++ b/frontend/app/player/mobile/utils.ts @@ -1,13 +1,7 @@ - -const iPhone12ProSvg2 = `` -const iPhone12ProMaxSvg2 = `` -const iphone14ProSvg2 = `` -const iphone14ProMaxSvg2 = `` -// old svg frames -// const iPhone12ProSvg = "" -// const iPhone12ProMaxSvg = "" -// const iphone14ProSvg = "" -// const iphone14ProMaxSvg = "" +const iPhone12ProSvg2 = ``; +const iPhone12ProMaxSvg2 = ``; +const iphone14ProSvg2 = ``; +const iphone14ProMaxSvg2 = ``; const screenResolutions = { iPhone12Pro: { @@ -66,38 +60,104 @@ const screenResolutions = { * everything else is considered as 12 pro * */ export function mapIphoneModel(modelName: string) { - const iPhone12Pro = [ - "iPhone 12", - "iPhone 12 Pro", - "iPhone 13", - "iPhone 13 Pro", - "iPhone 14" + 'iPhone 12', + 'iPhone 12 Pro', + 'iPhone 13', + 'iPhone 13 Pro', + 'iPhone 14', ]; const iPhone12ProMax = [ - "iPhone 12 Pro Max", - "iPhone 13 Pro Max", - "iPhone 14 Plus" + 'iPhone 12 Pro Max', + 'iPhone 13 Pro Max', + 'iPhone 14 Plus', ]; - const iPhone14Pro = [ - "iPhone 14 Pro" - ]; + const iPhone14Pro = ['iPhone 14 Pro']; - const iPhone14ProMax = [ - "iPhone 14 Pro Max" - ]; + const iPhone14ProMax = ['iPhone 14 Pro Max']; if (iPhone12Pro.includes(modelName)) { - return { svg: iPhone12ProSvg2, styles: screenResolutions.iPhone12Pro } as const; + return { + svg: iPhone12ProSvg2, + styles: screenResolutions.iPhone12Pro, + } as const; } else if (iPhone12ProMax.includes(modelName)) { - return { svg: iPhone12ProMaxSvg2, styles: screenResolutions.iPhone12ProMax } as const; + return { + svg: iPhone12ProMaxSvg2, + styles: screenResolutions.iPhone12ProMax, + } as const; } else if (iPhone14Pro.includes(modelName)) { - return { svg: iphone14ProSvg2, styles: screenResolutions.iPhone14Pro } as const; + return { + svg: iphone14ProSvg2, + styles: screenResolutions.iPhone14Pro, + } as const; } else if (iPhone14ProMax.includes(modelName)) { - return { svg: iphone14ProMaxSvg2, styles: screenResolutions.iPhone14ProMax } as const; + return { + svg: iphone14ProMaxSvg2, + styles: screenResolutions.iPhone14ProMax, + } as const; } else { - return { svg: iPhone12ProSvg2, styles: screenResolutions.iPhone12Pro} as const; // Default fallback + return { + svg: iPhone12ProSvg2, + styles: screenResolutions.iPhone12Pro, + } as const; // Default fallback } } + +const universalAndroid = (width: number, height: number) => { + const scale = width / 375; + const strokeWidth = Math.round(6 * scale); + const radius = Math.round(20 * scale); + + const dot = 15 * scale; + + const phoneStyle = `margin-top: ${strokeWidth}px; margin-left: ${strokeWidth}px; width: ${width}px; height: ${height}px; border-radius: ${radius}px; overflow: hidden; outline:${strokeWidth}px solid black;border: ${strokeWidth}px solid #444; position: relative;`; + const cameraStyle = `width:${dot}px;height:${dot}px;background:#111921;background:conic-gradient(from 315deg,#111921,#2E303D);border-radius:50%;position:absolute;top:${ + scale * 10 + }px;left:50%;transform:translateX(-50%);z-index:9`; + const screenStyle = `width: ${width}px; height: ${height}px; z-index: 6;`; + const casingStyle = `position: relative;`; + const rockersStyle = `position: absolute; top: 30%; right: -${ + strokeWidth * 2 + }px; display: flex; flex-direction: column; z-index: 9; gap: ${scale * 6}px;`; + const volumeButtonStyle = `width: ${8 * scale}px; height: ${ + 60 * scale + }px; background: black; border-top-right-radius: ${ + 2 * scale + }px; border-bottom-right-radius: ${2 * scale}px;`; + return { + svg: `
+
+
+
+
+
+
+
+
`, + strokeWidth, + }; +}; + +export function mapAndroidModel(width: number, height: number) { + const { svg, strokeWidth } = universalAndroid(width, height); + + return { + svg, + styles: { + // two borders + margin: `${strokeWidth * 2}px 0 0 ${strokeWidth * 2}px`, + screen: { + width, + height, + }, + shell: { + // 2 borders, margins and volume buttons + width: width + 4 * strokeWidth + 15, + height: height + 4 * strokeWidth, + }, + }, + }; +}