Merge branch 'develop' into feat/emoji-picker-rich-text-mode

pull/28788/head^2
Andy Balaam 2022-12-08 09:39:30 +00:00 committed by GitHub
commit 0f17728aa1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 61 additions and 28 deletions

View File

@ -53,7 +53,9 @@ limitations under the License.
height: var(--size); height: var(--size);
border-radius: 5px; border-radius: 5px;
} }
}
.mx_FormattingButtons_Button_hover {
&:hover { &:hover {
&::after { &::after {
background: rgba($secondary-content, 0.1); background: rgba($secondary-content, 0.1);

View File

@ -48,7 +48,10 @@ function Button({ label, keyCombo, onClick, isActive, className }: ButtonProps)
onClick={onClick} onClick={onClick}
title={label} title={label}
className={ className={
classNames('mx_FormattingButtons_Button', className, { 'mx_FormattingButtons_active': isActive })} classNames('mx_FormattingButtons_Button', className, {
'mx_FormattingButtons_active': isActive,
'mx_FormattingButtons_Button_hover': !isActive,
})}
tooltip={keyCombo && <Tooltip label={label} keyCombo={keyCombo} />} tooltip={keyCombo && <Tooltip label={label} keyCombo={keyCombo} />}
alignment={Alignment.Top} alignment={Alignment.Top}
/>; />;

View File

@ -143,13 +143,14 @@ export class VoiceBroadcastPlayback
return false; return false;
} }
if (!event.getId() && !event.getTxnId()) {
// skip events without id and txn id
return false;
}
this.chunkEvents.addEvent(event); this.chunkEvents.addEvent(event);
this.setDuration(this.chunkEvents.getLength()); this.setDuration(this.chunkEvents.getLength());
if (this.getState() !== VoiceBroadcastPlaybackState.Stopped) {
await this.enqueueChunk(event);
}
if (this.getState() === VoiceBroadcastPlaybackState.Buffering) { if (this.getState() === VoiceBroadcastPlaybackState.Buffering) {
await this.start(); await this.start();
this.updateLiveness(); this.updateLiveness();
@ -183,18 +184,7 @@ export class VoiceBroadcastPlayback
} }
}; };
private async enqueueChunks(): Promise<void> { private async loadPlayback(chunkEvent: MatrixEvent): Promise<void> {
const promises = this.chunkEvents.getEvents().reduce((promises, event: MatrixEvent) => {
if (!this.playbacks.has(event.getId() || "")) {
promises.push(this.enqueueChunk(event));
}
return promises;
}, [] as Promise<void>[]);
await Promise.all(promises);
}
private async enqueueChunk(chunkEvent: MatrixEvent): Promise<void> {
const eventId = chunkEvent.getId(); const eventId = chunkEvent.getId();
if (!eventId) { if (!eventId) {
@ -215,6 +205,14 @@ export class VoiceBroadcastPlayback
}); });
} }
private unloadPlayback(event: MatrixEvent): void {
const playback = this.playbacks.get(event.getId()!);
if (!playback) return;
playback.destroy();
this.playbacks.delete(event.getId()!);
}
private onPlaybackPositionUpdate = ( private onPlaybackPositionUpdate = (
event: MatrixEvent, event: MatrixEvent,
position: number, position: number,
@ -261,6 +259,7 @@ export class VoiceBroadcastPlayback
if (newState !== PlaybackState.Stopped) return; if (newState !== PlaybackState.Stopped) return;
await this.playNext(); await this.playNext();
this.unloadPlayback(event);
}; };
private async playNext(): Promise<void> { private async playNext(): Promise<void> {
@ -283,10 +282,11 @@ export class VoiceBroadcastPlayback
private async playEvent(event: MatrixEvent): Promise<void> { private async playEvent(event: MatrixEvent): Promise<void> {
this.setState(VoiceBroadcastPlaybackState.Playing); this.setState(VoiceBroadcastPlaybackState.Playing);
this.currentlyPlaying = event; this.currentlyPlaying = event;
await this.getPlaybackForEvent(event)?.play(); const playback = await this.getOrLoadPlaybackForEvent(event);
playback?.play();
} }
private getPlaybackForEvent(event: MatrixEvent): Playback | undefined { private async getOrLoadPlaybackForEvent(event: MatrixEvent): Promise<Playback | undefined> {
const eventId = event.getId(); const eventId = event.getId();
if (!eventId) { if (!eventId) {
@ -294,6 +294,10 @@ export class VoiceBroadcastPlayback
return; return;
} }
if (!this.playbacks.has(eventId)) {
await this.loadPlayback(event);
}
const playback = this.playbacks.get(eventId); const playback = this.playbacks.get(eventId);
if (!playback) { if (!playback) {
@ -301,9 +305,18 @@ export class VoiceBroadcastPlayback
logger.warn("unable to find playback for event", event); logger.warn("unable to find playback for event", event);
} }
// try to load the playback for the next event for a smooth(er) playback
const nextEvent = this.chunkEvents.getNext(event);
if (nextEvent) this.loadPlayback(nextEvent);
return playback; return playback;
} }
private getCurrentPlayback(): Playback | undefined {
if (!this.currentlyPlaying) return;
return this.playbacks.get(this.currentlyPlaying.getId()!);
}
public getLiveness(): VoiceBroadcastLiveness { public getLiveness(): VoiceBroadcastLiveness {
return this.liveness; return this.liveness;
} }
@ -365,11 +378,8 @@ export class VoiceBroadcastPlayback
return; return;
} }
const currentPlayback = this.currentlyPlaying const currentPlayback = this.getCurrentPlayback();
? this.getPlaybackForEvent(this.currentlyPlaying) const skipToPlayback = await this.getOrLoadPlaybackForEvent(event);
: null;
const skipToPlayback = this.getPlaybackForEvent(event);
if (!skipToPlayback) { if (!skipToPlayback) {
logger.warn("voice broadcast chunk to skip to not found", event); logger.warn("voice broadcast chunk to skip to not found", event);
@ -396,14 +406,13 @@ export class VoiceBroadcastPlayback
} }
public async start(): Promise<void> { public async start(): Promise<void> {
await this.enqueueChunks();
const chunkEvents = this.chunkEvents.getEvents(); const chunkEvents = this.chunkEvents.getEvents();
const toPlay = this.getInfoState() === VoiceBroadcastInfoState.Stopped const toPlay = this.getInfoState() === VoiceBroadcastInfoState.Stopped
? chunkEvents[0] // start at the beginning for an ended voice broadcast ? chunkEvents[0] // start at the beginning for an ended voice broadcast
: chunkEvents[chunkEvents.length - 1]; // start at the current chunk for an ongoing voice broadcast : chunkEvents[chunkEvents.length - 1]; // start at the current chunk for an ongoing voice broadcast
if (this.playbacks.has(toPlay?.getId() || "")) { if (toPlay) {
return this.playEvent(toPlay); return this.playEvent(toPlay);
} }
@ -422,7 +431,7 @@ export class VoiceBroadcastPlayback
this.setState(VoiceBroadcastPlaybackState.Paused); this.setState(VoiceBroadcastPlaybackState.Paused);
if (!this.currentlyPlaying) return; if (!this.currentlyPlaying) return;
this.getPlaybackForEvent(this.currentlyPlaying)?.pause(); this.getCurrentPlayback()?.pause();
} }
public resume(): void { public resume(): void {
@ -433,7 +442,7 @@ export class VoiceBroadcastPlayback
} }
this.setState(VoiceBroadcastPlaybackState.Playing); this.setState(VoiceBroadcastPlaybackState.Playing);
this.getPlaybackForEvent(this.currentlyPlaying)?.play(); this.getCurrentPlayback()?.play();
} }
/** /**

View File

@ -75,4 +75,20 @@ describe('FormattingButtons', () => {
// Then // Then
expect(await screen.findByText('Bold')).toBeTruthy(); expect(await screen.findByText('Bold')).toBeTruthy();
}); });
it('Should not have hover style when active', async () => {
// When
const user = userEvent.setup();
render(<FormattingButtons composer={wysiwyg} actionStates={actionStates} />);
await user.hover(screen.getByLabelText('Bold'));
// Then
expect(screen.getByLabelText('Bold')).not.toHaveClass('mx_FormattingButtons_Button_hover');
// When
await user.hover(screen.getByLabelText('Underline'));
// Then
expect(screen.getByLabelText('Underline')).toHaveClass('mx_FormattingButtons_Button_hover');
});
}); });

View File

@ -387,6 +387,9 @@ describe("VoiceBroadcastPlayback", () => {
}); });
it("should play until the end", () => { it("should play until the end", () => {
// assert first chunk was unloaded
expect(chunk1Playback.destroy).toHaveBeenCalled();
// assert that the second chunk is being played // assert that the second chunk is being played
expect(chunk2Playback.play).toHaveBeenCalled(); expect(chunk2Playback.play).toHaveBeenCalled();