Skip to content

Commit

Permalink
Revert "Revert "feat(CR-152): add API for commit and restore cues (#45)…
Browse files Browse the repository at this point in the history
…" (#46)"

This reverts commit 42fe274.
  • Loading branch information
MosheMaorKaltura authored Dec 15, 2024
1 parent 42fe274 commit 66ad388
Show file tree
Hide file tree
Showing 7 changed files with 245 additions and 192 deletions.
67 changes: 47 additions & 20 deletions cypress/e2e/timeline.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ describe('Timeline plugin', () => {
mockKalturaBe();
loadPlayer().then(player => {
const timelineService = player.getService('timeline');
cy.stub(timelineService, '_isDurationCorrect', () => true);
cy.stub(timelineService.timelineManager, '_isDurationCorrect', () => true);
timelineService.addKalturaCuePoint(10, 'Hotspot', '1');
cy.get('[data-testid="cuePointContainer"]').should('exist');
cy.wait(1000);
Expand All @@ -249,7 +249,7 @@ describe('Timeline plugin', () => {
mockKalturaBe();
loadPlayer().then(player => {
const timelineService = player.getService('timeline');
cy.stub(timelineService, '_isDurationCorrect', () => true);
cy.stub(timelineService.timelineManager, '_isDurationCorrect', () => true);
timelineService.addKalturaCuePoint(0, 'Chapter', '1', 'Chapter 1');
timelineService.addKalturaCuePoint(18, 'Chapter', '2', 'Chapter 2');
cy.get('[data-testid="segmentsWrapper"]').should('exist');
Expand All @@ -261,7 +261,7 @@ describe('Timeline plugin', () => {
mockKalturaBe();
loadPlayer().then(player => {
const timelineService = player.getService('timeline');
cy.stub(timelineService, '_isDurationCorrect', () => true);
cy.stub(timelineService.timelineManager, '_isDurationCorrect', () => true);
timelineService.addKalturaCuePoint(10, 'Chapter', '1', 'Chapter 1');
timelineService.addKalturaCuePoint(18, 'Chapter', '2', 'Chapter 2');
cy.get('[data-testid="segmentsWrapper"]').should('exist');
Expand All @@ -273,7 +273,7 @@ describe('Timeline plugin', () => {
mockKalturaBe();
loadPlayer().then(player => {
const timelineService = player.getService('timeline');
cy.stub(timelineService, '_isDurationCorrect', () => true);
cy.stub(timelineService.timelineManager, '_isDurationCorrect', () => true);
timelineService.addKalturaCuePoint(10, 'Chapter', '1', 'Chapter 1');
timelineService.addKalturaCuePoint(18, 'Chapter', '2', 'Chapter 2');
cy.get('[data-testid="segmentsWrapper"]').should('exist');
Expand All @@ -299,7 +299,7 @@ describe('Timeline plugin', () => {
mockKalturaBe();
loadPlayer().then(player => {
const timelineService = player.getService('timeline');
cy.stub(timelineService, '_isDurationCorrect', () => true);
cy.stub(timelineService.timelineManager, '_isDurationCorrect', () => true);
timelineService.addKalturaCuePoint(0, 'Chapter', '1', 'Chapter 1');
timelineService.addKalturaCuePoint(18, 'Chapter', '2', 'Chapter 2');
cy.get('[data-testid="segmentsWrapper"]').should('exist');
Expand All @@ -321,6 +321,26 @@ describe('Timeline plugin', () => {
});
});
});

it('Should trigger callback method on previes click', done => {
mockKalturaBe();
loadPlayer().then(player => {
const timelineService = player.getService('timeline');
cy.stub(timelineService.timelineManager, '_isDurationCorrect', () => true);
const callback = cy.stub();
timelineService.addKalturaCuePoint(10, 'Hotspot', '1', 'Hotspot 1', {onClick: callback});
cy.get('[data-testid="cuePointContainer"]').should('exist');
cy.wait(1000);
cy.get('[data-testid="cuePointMarkerContainer"]').focus();
cy.get('[data-testid="cuePointPreviewHeaderTitle"]').should('have.text', 'Hotspot');
cy.get('[data-testid="cuePointPreviewHeaderTitle"]')
.click({force: true})
.then(() => {
expect(callback).to.have.been.called;
done();
});
});
});
});

describe('removeCuePoint', () => {
Expand All @@ -340,44 +360,51 @@ describe('Timeline plugin', () => {
});
});
});

it('Should remove all added cue points', done => {
mockKalturaBe();
loadPlayer().then(player => {
const timelineService = player.getService('timeline');
cy.stub(timelineService.timelineManager, '_isDurationCorrect', () => true);
timelineService.addKalturaCuePoint(0, 'Chapter', '1', 'Chapter 1');
timelineService.addKalturaCuePoint(18, 'Chapter', '2', 'Chapter 2');
cy.get('[data-testid="segmentsWrapper"]').children().should('have.length', 2);
timelineService.removeAllKalturaCuePoints();
setTimeout(() => {
cy.get('[data-testid="segmentsWrapper"]').children().should('have.length', 0);
done();
}, 500);
});
});
});

describe('dual-screen timeline preview', () => {
it('Should test single preview on segments', () => {
mockKalturaBe();
loadPlayer().then(player => {
const fakeDualScreenPlugin = {
getDualScreenThumbs: (time: number) => player.getThumbnail(time)
};
player.registerService('dualScreen', fakeDualScreenPlugin);
const timelineService = player.getService('timeline');
cy.stub(timelineService, '_isDurationCorrect', () => true);
timelineService.setGetThumbnailInfo((time: number) => player.getThumbnail(time));
cy.stub(timelineService.timelineManager, '_isDurationCorrect', () => true);
timelineService.addKalturaCuePoint(10, 'Chapter', '1', 'Chapter 1');
cy.get('[data-testid="cuePointPreviewImageContainer"]').children().should('have.length', 1);
});
});
it('Should test dual preview on segments', () => {
mockKalturaBe();
loadPlayer().then(player => {
const fakeDualScreenPlugin = {
getDualScreenThumbs: (time: number) => [player.getThumbnail(time), player.getThumbnail(time)]
};
player.registerService('dualScreen', fakeDualScreenPlugin);
const timelineService = player.getService('timeline');
cy.stub(timelineService, '_isDurationCorrect', () => true);
timelineService.setGetThumbnailInfo((time: number) => [player.getThumbnail(time), player.getThumbnail(time)]);
cy.stub(timelineService.timelineManager, '_isDurationCorrect', () => true);
timelineService.addKalturaCuePoint(10, 'Chapter', '1', 'Chapter 1');
cy.get('[data-testid="cuePointPreviewImageContainer"]').children().should('have.length', 2);
});
});
it('Should test dual preview', () => {
mockKalturaBe();
loadPlayer().then(player => {
const fakeDualScreenPlugin = {
getDualScreenThumbs: (time: number) => [player.getThumbnail(time), player.getThumbnail(time)]
};
player.registerService('dualScreen', fakeDualScreenPlugin);
const timelineService = player.getService('timeline');
timelineService._addSeekBarPreview();
timelineService.setGetThumbnailInfo((time: number) => [player.getThumbnail(time), player.getThumbnail(time)]);
timelineService.addSeekBarPreview();
cy.get('[data-testid="cuePointPreviewImageContainer"]').children().should('have.length', 2);
});
});
Expand Down
8 changes: 6 additions & 2 deletions cypress/e2e/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ const getPlayer = () => {
};

const preparePage = (pluginConf = {}, playbackConf = {}) => {
cy.visit('index.html');
cy.visit('index.html', {
onBeforeLoad: (contentWindow: any) => {
contentWindow._TEST_ENV = true;
}
});
return cy.window().then(win => {
try {
// @ts-ignore
Expand All @@ -19,7 +23,7 @@ const preparePage = (pluginConf = {}, playbackConf = {}) => {
},
playback: {muted: true, autoplay: true, ...playbackConf},
plugins: {
timeline: {}
timeline: pluginConf
}
});
return kalturaPlayer.loadMedia({entryId: '0_wifqaipd'});
Expand Down
99 changes: 56 additions & 43 deletions flow-typed/types/cue-point-option.ts
Original file line number Diff line number Diff line change
@@ -1,69 +1,82 @@
import {OnClickEvent} from '@playkit-js/common/dist/hoc/a11y-wrapper';
import {ItemTypes} from '../../src/types/timelineTypes';

export type CuePointOptionsObject = {
marker?: MarkerOptionsObject,
preview?: PreviewOptionsObject
marker?: MarkerOptionsObject;
preview?: PreviewOptionsObject;
};

export type TimedCuePointOptionsObject = CuePointOptionsObject & {
time: number,
presets?: Array<string>
time: number;
presets?: Array<string>;
};

export type KalturaCuePointOptionsObject = {
startTime: number,
type: string,
cuePointId: string,
title?: string,
quizQuestionData?: QuizQuestionData
startTime: number;
type: string;
cuePointId: string;
title?: string;
cuePointData?: QuizQuestionData;
};

export type QuizQuestionData = {
onClick: () => void,
isMarkerDisabled: () => boolean,
index: number,
type: number
onClick: () => void;
isMarkerDisabled: () => boolean;
index: number;
type: number;
};

export type NavigationChapterData = {
onClick?: (
e: OnClickEvent,
byKeyboard: boolean,
cuePoint: {startTime: number; type: ItemTypes.Chapter; cuePointId: string; title?: string}
) => void;
};

export type MarkerOptionsObject = {
get?: Function | string,
props?: Object,
color?: string,
width?: number,
className?: string
get?: Function | string;
props?: Object;
color?: string;
width?: number;
className?: string;
};

export type PreviewOptionsObject = {
get?: Function | string,
props?: Object,
width?: number,
height?: number,
className?: string,
hideTime?: boolean,
sticky?: boolean
get?: Function | string;
props?: Object;
width?: number;
height?: number;
className?: string;
hideTime?: boolean;
sticky?: boolean;
};

export type TimelineMarkerDataObject = MarkerOptionsObject & {
cuePoints: Array<string>,
id?: string,
timelinePreviewRef: any,
timelineMarkerRef: any,
cuePointsData: Array<CuePointMarker>,
useQuizQuestionMarkerSize: boolean,
onMarkerClick: any,
isMarkerDisabled: any
id?: string;
timelinePreviewRef: any;
timelineMarkerRef: any;
cuePointsData: Array<CuePointMarker>;
useQuizQuestionMarkerSize: boolean;
onMarkerClick: any;
isMarkerDisabled: any;
onPreviewClick: (e: OnClickEvent, byKeyboard: boolean) => void;
};

export type CuePointMarker = {
id: string,
type: string,
title: string,
quizQuestionData: any
id: string;
type: string;
title: string;
cuePointData: any;
};

export type Chapter = {
id: string,
title: string,
startTime: number,
endTime: number,
isDummy?: boolean,
isHovered: boolean
id: string;
type: ItemTypes.Chapter;
title: string;
startTime: number;
endTime: number;
isDummy?: boolean;
isHovered: boolean;
onPreviewClick: (e: OnClickEvent, byKeyboard: boolean, chapter: Chapter) => void;
};
7 changes: 5 additions & 2 deletions src/components/chapters/segments-wrapper.scss
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
position: absolute;
}

.chapters-container > div:not(:last-child) {
margin-right: 2px;
.chapters-container > div {
border-radius: 4px;
&:not(:last-child) {
margin-right: 4px;
}
}
17 changes: 10 additions & 7 deletions src/components/marker/timeline-preview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const translates = {
};

interface TimelinePreviewProps {
toggleNavigationPlugin: (e: OnClickEvent, byKeyboard: boolean, cuePointType: string) => void;
onPreviewClick: (e: OnClickEvent, byKeyboard: boolean, chapter: Chapter) => void;
seekTo: () => void;
cuePointsData: Array<CuePointMarker>;
getThumbnailInfo: () => ThumbnailInfo | ThumbnailInfo[];
Expand Down Expand Up @@ -99,7 +99,11 @@ const Title = ({iconName, children, shouldDisplayTitle = true}: TitleProps) => {
return (
<div className={styles.titleWrapper}>
<Icon size={IconSize.small} name={iconName} />
{shouldDisplayTitle && <span className={styles.title}>{children}</span>}
{shouldDisplayTitle && (
<span className={styles.title} data-testid="cuePointPreviewHeaderTitle">
{children}
</span>
)}
</div>
);
};
Expand Down Expand Up @@ -170,11 +174,11 @@ export class TimelinePreview extends Component<TimelinePreviewProps> {
let quizQuestionTitle = {type: '', firstIndex: 1, lastIndex: ''};
if (quizQuestions.length) {
//@ts-ignore
const reflectionPoint = quizQuestions.find(qq => qq.quizQuestionData.type === 3);
const reflectionPoint = quizQuestions.find(qq => qq.cuePointData.type === 3);
quizQuestionTitle = {
type: quizQuestions.length === 1 && reflectionPoint ? this.props.reflectionPointTranslate! : this.props.questionTranslate!,
firstIndex: quizQuestions[0].quizQuestionData.index + 1,
lastIndex: quizQuestions.length > 1 ? `-${quizQuestions[quizQuestions.length - 1].quizQuestionData.index + 1}` : ''
firstIndex: quizQuestions[0].cuePointData.index + 1,
lastIndex: quizQuestions.length > 1 ? `-${quizQuestions[quizQuestions.length - 1].cuePointData.index + 1}` : ''
};
}

Expand Down Expand Up @@ -279,8 +283,7 @@ export class TimelinePreview extends Component<TimelinePreviewProps> {

onPreviewHeaderClick = (e: OnClickEvent, byKeyboard: boolean) => {
const relevantQuizQuestion = this.props.cuePointsData.find(cp => cp.type === ItemTypes.QuizQuestion);
relevantQuizQuestion ? relevantQuizQuestion.quizQuestionData?.onClick() : this.props.seekTo();
this.props.toggleNavigationPlugin(e, byKeyboard, this.props.cuePointsData[0]?.type || ItemTypes.Chapter);
relevantQuizQuestion ? relevantQuizQuestion.cuePointData?.onClick() : this.props.onPreviewClick(e, byKeyboard, this.props.relevantChapter!);
};

_getPreviewHeaderLeft(): number | null {
Expand Down
Loading

0 comments on commit 66ad388

Please sign in to comment.