Skip to content
This repository was archived by the owner on Apr 18, 2024. It is now read-only.
Merged
44 changes: 23 additions & 21 deletions e2e/tests/sync/audio-paragraphs.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,16 +54,16 @@ const data = {
url: 'https://htx-misc.s3.amazonaws.com/opensource/label-studio/examples/audio/barradeen-emotional.mp3',
text: [
{
'end': 2,
'end': 3,
'text': 'Dont you hate that?',
'start': 0,
'start': 1,
'author': 'Mia Wallace',
},
{
'text': 'Hate what?',
'start': 2,
'start': 3,
'author': 'Vincent Vega:',
'duration': 2,
'duration': 1,
},
{
'text': 'Uncomfortable silences. Why do we feel its necessary to yak about bullshit in order to be comfortable?',
Expand Down Expand Up @@ -172,10 +172,10 @@ FFlagMatrix(['fflag_feat_front_lsdv_e_278_contextual_scrolling_short'], function
assert.equal(startingAudioTime, startingParagraphAudioTime);
assert.equal(startingParagraphAudioTime, 0);

I.click('[aria-label="play-circle"]');
I.click('[aria-label="play"]');
I.wait(1);

I.click('[aria-label="pause-circle"]');
I.click('[aria-label="play"]');
I.wait(1);

const [{ currentTime: seekAudioTime }, { currentTime: seekParagraphAudioTime }] = await AtAudioView.getCurrentAudio();
Expand Down Expand Up @@ -209,29 +209,29 @@ FFlagMatrix(['fflag_feat_front_lsdv_e_278_contextual_scrolling_short'], function
AtAudioView.clickPauseButton();

// Plays the first paragraph segment when the audio interface is played
I.seeElement('[data-testid="phrase:0"] [aria-label="pause-circle"]');
I.seeElement('[data-testid="phrase:1"] [aria-label="play-circle"]');
I.seeElement('[data-testid="phrase:2"] [aria-label="play-circle"]');
I.seeElement('[data-testid="phrase:3"] [aria-label="play-circle"]');
I.seeElement('[data-testid="phrase:4"] [aria-label="play-circle"]');
I.seeElement('[data-testid="phrase:0"] [aria-label="pause"]');
I.seeElement('[data-testid="phrase:1"] [aria-label="play"]');
I.seeElement('[data-testid="phrase:2"] [aria-label="play"]');
I.seeElement('[data-testid="phrase:3"] [aria-label="play"]');
I.seeElement('[data-testid="phrase:4"] [aria-label="play"]');

I.wait(2);

// Plays the second paragraph segment when the audio progresses to the second paragraph segment
I.seeElement('[data-testid="phrase:1"] [aria-label="pause-circle"]');
I.seeElement('[data-testid="phrase:0"] [aria-label="play-circle"]');
I.seeElement('[data-testid="phrase:2"] [aria-label="play-circle"]');
I.seeElement('[data-testid="phrase:3"] [aria-label="play-circle"]');
I.seeElement('[data-testid="phrase:4"] [aria-label="play-circle"]');
I.seeElement('[data-testid="phrase:1"] [aria-label="pause"]');
I.seeElement('[data-testid="phrase:0"] [aria-label="play"]');
I.seeElement('[data-testid="phrase:2"] [aria-label="play"]');
I.seeElement('[data-testid="phrase:3"] [aria-label="play"]');
I.seeElement('[data-testid="phrase:4"] [aria-label="play"]');

I.wait(2);

// Plays the third paragraph segment when the audio progresses to the third paragraph segment
I.seeElement('[data-testid="phrase:2"] [aria-label="pause-circle"]');
I.seeElement('[data-testid="phrase:0"] [aria-label="play-circle"]');
I.seeElement('[data-testid="phrase:1"] [aria-label="play-circle"]');
I.seeElement('[data-testid="phrase:3"] [aria-label="play-circle"]');
I.seeElement('[data-testid="phrase:4"] [aria-label="play-circle"]');
I.seeElement('[data-testid="phrase:2"] [aria-label="pause"]');
I.seeElement('[data-testid="phrase:0"] [aria-label="play"]');
I.seeElement('[data-testid="phrase:1"] [aria-label="play"]');
I.seeElement('[data-testid="phrase:3"] [aria-label="play"]');
I.seeElement('[data-testid="phrase:4"] [aria-label="play"]');
});

FFlagScenario('Check if paragraph is scrolling automatically following the audio', async function({ I, LabelStudio, AtAudioView }) {
Expand Down Expand Up @@ -298,6 +298,8 @@ FFlagMatrix(['fflag_feat_front_lsdv_e_278_contextual_scrolling_short'], function

AtAudioView.clickAtBeginning();

I.wait(1);

AtAudioView.clickPauseButton();

const scrollPosition = await I.executeScript(function(selector) {
Expand Down
8 changes: 4 additions & 4 deletions e2e/tests/sync/audio-video-paragraphs.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ FFlagMatrix([
assert.equal(startingParagraphAudioTime, 0);
}

I.click('[aria-label="play-circle"]');
I.click('[aria-label="play"]');
I.wait(1);
{
I.say('Audio, Video, and Paragraph Audio are playing');
Expand All @@ -134,7 +134,7 @@ FFlagMatrix([
assert.equal(paragraphAudioPaused, false);
}

I.click('[aria-label="pause-circle"]');
I.click('[aria-label="pause"]');
I.wait(1);
{
I.say('Audio, Video and Paragraph Audio are played to the same time and are now paused');
Expand Down Expand Up @@ -307,9 +307,9 @@ FFlagMatrix([
assert.equal(startingAudioTime, startingVideoTime);
}

I.click('[aria-label="play-circle"]');
I.click('[aria-label="play"]');
I.wait(1);
I.click('[aria-label="pause-circle"]');
I.click('[aria-label="pause"]');
I.wait(1);
{
I.say('Seek playback from paragraph. Audio, video and paragraph audio are played to the same time and are now paused');
Expand Down
2 changes: 2 additions & 0 deletions src/assets/icons/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ export { ReactComponent as IconFast } from './fast.svg';
export { ReactComponent as IconDuplicate } from './duplicate.svg';
export { ReactComponent as IconEllipsis } from './ellipsis.svg';
export { ReactComponent as IconWarning } from './warning.svg';
export { ReactComponent as IconPlay } from './play.svg';
export { ReactComponent as IconPause } from './pause.svg';
export { ReactComponent as IconHelp } from './help.svg';

export { ReactComponent as IconCheck } from './check.svg';
Expand Down
4 changes: 4 additions & 0 deletions src/assets/icons/pause.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions src/assets/icons/play.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
79 changes: 77 additions & 2 deletions src/tags/object/Paragraphs/Paragraphs.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ $border-thin: 1px solid rgba(137, 128, 152, 0.16);

.dialoguename {
font-weight: bold;
background: white !important;
background: white;
border-radius: 5px;
padding: 5px;
margin-right: 10px;
Expand All @@ -63,7 +63,8 @@ $border-thin: 1px solid rgba(137, 128, 152, 0.16);

.scroll_container {
position: relative;
overflow: auto;
overflow-y: auto;
overflow-x: hidden;
counter-reset: phrase;
border: $border-thin;
padding: 8px;
Expand Down Expand Up @@ -166,6 +167,19 @@ $border-thin: 1px solid rgba(137, 128, 152, 0.16);
z-index: 1;
}

.playNewUi {
user-select: none;
cursor: pointer;
position: absolute;
left: 5px;
margin-top: -0.3em;
font-size: inherit;

&:hover, &:active, &:focus {
background: none;
}
}

.play {
user-select: none;
position: absolute;
Expand All @@ -183,3 +197,64 @@ $border-thin: 1px solid rgba(137, 128, 152, 0.16);
fill: #1890ff;
}
}

.newUI {
transition: all .1s ease-out;
border-radius: 4px;
display: flex;
flex-wrap: wrap;
width: calc(100% - 36px);

&.collapsed {
background-color: var(--highlight-color);
border: 1px solid var(--highlight-color);
}

&:not(.collapsed) {
background-color: var(--background-color);
border-left: 4px solid var(--highlight-color);
border-top: 1px solid rgba(137, 128, 152, 0.16);
border-bottom: 1px solid rgba(137, 128, 152, 0.16);
border-right: 1px solid rgba(137, 128, 152, 0.16);
padding: 8px 12px 8px 12px;
}

.dialoguename {
transition: all .1s ease-out;
background: none;
font-size: 16px;
font-style: normal;
font-weight: 500;
line-height: 24px;
letter-spacing: 0.15px;
padding: 0
}

.dialoguetext {
transition: all .1s ease-out;
font-size: 14px;
font-style: normal;
font-weight: 400;
line-height: 20px;
letter-spacing: 0.25px;
color: #1F1F1F;
width: 100%;
margin-top: 8px;
}

.titleWrapper {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;

.time {
font-size: 12px;
font-style: normal;
font-weight: 500;
line-height: 16px;
letter-spacing: 0.5px;
color: #898098;
}
}
}
50 changes: 44 additions & 6 deletions src/tags/object/Paragraphs/Phrases.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,22 @@ import { getRoot } from 'mobx-state-tree';
import { Button } from 'antd';
import { PauseCircleOutlined, PlayCircleOutlined } from '@ant-design/icons';
import styles from './Paragraphs.module.scss';
import { FF_LSDV_E_278, isFF } from '../../../utils/feature-flags';
import { IconPause, IconPlay } from '../../../assets/icons';

const formatTime = (seconds) => {
if (isNaN(seconds)) return '';

const hours = Math.floor(seconds / 3600);
const minutes = Math.floor((seconds % 3600) / 60);
const remainingSeconds = Math.round(seconds % 60);

const formattedHours = String(hours).padStart(2, '0');
const formattedMinutes = String(minutes).padStart(2, '0');
const formattedSeconds = String(remainingSeconds).padStart(2, '0');

return `${formattedHours}:${formattedMinutes}:${formattedSeconds}`;
};

export const Phrases = observer(({ item, playingId, activeRef }) => {
const cls = item.layoutClasses;
Expand All @@ -11,26 +27,48 @@ export const Phrases = observer(({ item, playingId, activeRef }) => {
if (!item._value) return null;

const val = item._value.map((v, idx) => {
const style = item.layoutStyles(v);
const isActive = playingId === idx;
const isPlaying = isActive && item.playing;
const style = (isFF(FF_LSDV_E_278) && !isActive) ? item.layoutStyles(v).inactive: item.layoutStyles(v);
const classNames = [cls.phrase];
const isContentVisible = item.isVisibleForAuthorFilter(v);
const isPlaying = playingId === idx && item.playing;

const withFormattedTime = (item) => {
const startTime = formatTime(item._value[idx]?.start);
const endTime = formatTime(!item._value[idx]?.end ? item._value[idx]?.start + item._value[idx]?.duration : item._value[idx]?.end);

return `${startTime} - ${endTime}`;
};

if (withAudio) classNames.push(styles.withAudio);
if (!isContentVisible) classNames.push(styles.collapsed);
if (getRoot(item).settings.showLineNumbers) classNames.push(styles.numbered);

return (
<div key={`${item.name}-${idx}`} ref={isPlaying ? activeRef : null} data-testid={`phrase:${idx}`} className={classNames.join(' ')} style={style.phrase}>
<div key={`${item.name}-${idx}`} ref={isActive ? activeRef : null} data-testid={`phrase:${idx}`} className={`${classNames.join(' ')} ${isFF(FF_LSDV_E_278) && styles.newUI}`} style={style.phrase}>
{isContentVisible && withAudio && !isNaN(v.start) && (
<Button
type="text"
className={styles.play}
icon={isPlaying ? <PauseCircleOutlined /> : <PlayCircleOutlined />}
className={isFF(FF_LSDV_E_278) ? styles.playNewUi : styles.play}
aria-label={isPlaying ? 'pause' : 'play'}
icon={isPlaying ?
isFF(FF_LSDV_E_278) ?
<IconPause /> : <PauseCircleOutlined /> :
isFF(FF_LSDV_E_278) ?
<IconPlay /> : <PlayCircleOutlined />
}
onClick={() => item.play(idx)}
/>
)}
<span className={cls.name} data-skip-node="true">{v[item.namekey]}</span>
{isFF(FF_LSDV_E_278) ? (
<span className={styles.titleWrapper} data-skip-node="true">
<span className={cls.name} style={style.name}>{v[item.namekey]}</span>
<span className={styles.time}>{withFormattedTime(item)}</span>
</span>
) : (
<span className={cls.name} data-skip-node="true" style={style.name}>{v[item.namekey]}</span>
)}

<span className={cls.text}>{v[item.textkey]}</span>
</div>
);
Expand Down
31 changes: 27 additions & 4 deletions src/tags/object/Paragraphs/model.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,10 +97,28 @@ const Model = types
layoutStyles(data) {
if (self.layout === 'dialogue') {
const seed = data[self.namekey];
const color = ColorScheme.make_color({ seed })[0];

return {
phrase: { backgroundColor: Utils.Colors.convertToRGBA(ColorScheme.make_color({ seed })[0], 0.25) },
};
if (isFF(FF_LSDV_E_278)) {
return {
phrase: {
'--highlight-color': color,
'--background-color': '#FFF',
},
name: { color },
inactive: {
phrase: {
'--highlight-color': Utils.Colors.convertToRGBA(color, 0.4),
'--background-color': '#FAFAFA',
},
name: { color: Utils.Colors.convertToRGBA(color, 0.9) },
},
};
} else {
return {
phrase: { backgroundColor: Utils.Colors.convertToRGBA(color, 0.25) },
};
}
}

return {};
Expand Down Expand Up @@ -186,6 +204,9 @@ const PlayableAndSyncable = types.model()
return { start, end };
});
},
get regionsValues() {
return Object.values(self.regionsStartEnd);
},
}))
.actions(self => ({
/**
Expand Down Expand Up @@ -236,6 +257,8 @@ const PlayableAndSyncable = types.model()
} else {
self.play(self.playingId);
}
} else if (isFF(FF_LSDV_E_278)) {
self.trackPlayingId();
}
},

Expand Down Expand Up @@ -313,7 +336,7 @@ const PlayableAndSyncable = types.model()
return;
}

const regions = Object.values(self.regionsStartEnd);
const regions = self.regionsValues;

self.playingId = regions.findIndex(({ start, end }) => {
return currentTime >= start && currentTime <= end;
Expand Down