MOBILE-4322 bbb: Display all playbacks in recordings
parent
d9e2788f44
commit
e49fa18261
|
@ -462,8 +462,6 @@
|
||||||
"addon.mod_bigbluebuttonbn.view_message_viewer": "bigbluebuttonbn",
|
"addon.mod_bigbluebuttonbn.view_message_viewer": "bigbluebuttonbn",
|
||||||
"addon.mod_bigbluebuttonbn.view_message_viewers": "bigbluebuttonbn",
|
"addon.mod_bigbluebuttonbn.view_message_viewers": "bigbluebuttonbn",
|
||||||
"addon.mod_bigbluebuttonbn.view_nojoin": "bigbluebuttonbn",
|
"addon.mod_bigbluebuttonbn.view_nojoin": "bigbluebuttonbn",
|
||||||
"addon.mod_bigbluebuttonbn.view_recording_format_presentation": "bigbluebuttonbn",
|
|
||||||
"addon.mod_bigbluebuttonbn.view_recording_list_action_play": "bigbluebuttonbn",
|
|
||||||
"addon.mod_bigbluebuttonbn.view_section_title_recordings": "bigbluebuttonbn",
|
"addon.mod_bigbluebuttonbn.view_section_title_recordings": "bigbluebuttonbn",
|
||||||
"addon.mod_book.errorchapter": "book",
|
"addon.mod_book.errorchapter": "book",
|
||||||
"addon.mod_book.modulenameplural": "book",
|
"addon.mod_book.modulenameplural": "book",
|
||||||
|
|
|
@ -90,9 +90,8 @@
|
||||||
</ion-label>
|
</ion-label>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
<ng-container *ngFor="let recording of recordings">
|
<ng-container *ngFor="let recording of recordings">
|
||||||
<ion-item *ngIf="recording.url" button class="addon-mod_bbb-recording-title" [attr.aria-expanded]="recording.expanded"
|
<ion-item button class="addon-mod_bbb-recording-title" [attr.aria-expanded]="recording.expanded" (click)="toggle(recording)"
|
||||||
(click)="toggle(recording)" [attr.aria-label]="(recording.expanded ? 'core.collapse' : 'core.expand') | translate"
|
[attr.aria-label]="(recording.expanded ? 'core.collapse' : 'core.expand') | translate" detail="false">
|
||||||
detail="false">
|
|
||||||
<ion-icon name="fas-chevron-right" flip-rtl slot="start" aria-hidden="true" class="expandable-status-icon"
|
<ion-icon name="fas-chevron-right" flip-rtl slot="start" aria-hidden="true" class="expandable-status-icon"
|
||||||
[class.expandable-status-icon-expanded]="recording.expanded">
|
[class.expandable-status-icon-expanded]="recording.expanded">
|
||||||
</ion-icon>
|
</ion-icon>
|
||||||
|
@ -100,12 +99,22 @@
|
||||||
<p>{{ recording.type }}</p>
|
<p>{{ recording.type }}</p>
|
||||||
<p>{{ recording.name }}</p>
|
<p>{{ recording.name }}</p>
|
||||||
</ion-label>
|
</ion-label>
|
||||||
<ion-button slot="end" fill="clear" (click)="playRecording($event, recording)"
|
|
||||||
[attr.aria-label]="'addon.mod_bigbluebuttonbn.view_recording_list_action_play' | translate">
|
|
||||||
<ion-icon name="fas-circle-play" slot="icon-only" aria-hidden="true"></ion-icon>
|
|
||||||
</ion-button>
|
|
||||||
</ion-item>
|
</ion-item>
|
||||||
<div [hidden]="!recording.expanded" class="addon-mod_bbb-recording-details">
|
<div [hidden]="!recording.expanded" class="addon-mod_bbb-recording-details">
|
||||||
|
<div *ngIf="recording.playbacks.length" class="addon-mod_bbb-recording-playbacks">
|
||||||
|
<ion-item class="ion-text-wrap addon-mod_bbb-recording-playback-title">
|
||||||
|
<ion-label>
|
||||||
|
<p class="item-heading">{{ recording.playbackLabel }}</p>
|
||||||
|
</ion-label>
|
||||||
|
</ion-item>
|
||||||
|
<ion-item *ngFor="let playback of recording.playbacks" button (click)="openPlayback($event, playback)"
|
||||||
|
class="ion-text-wrap addon-mod_bbb-recording-playback-item">
|
||||||
|
<ion-label>
|
||||||
|
<p>{{ playback.name }}</p>
|
||||||
|
</ion-label>
|
||||||
|
<ion-icon slot="end" [name]="playback.icon" aria-hidden="true"></ion-icon>
|
||||||
|
</ion-item>
|
||||||
|
</div>
|
||||||
<ion-item *ngFor="let data of recording.details" class="ion-text-wrap">
|
<ion-item *ngFor="let data of recording.details" class="ion-text-wrap">
|
||||||
<ion-label>
|
<ion-label>
|
||||||
<p class="item-heading">{{ data.label }}</p>
|
<p class="item-heading">{{ data.label }}</p>
|
||||||
|
|
|
@ -10,6 +10,10 @@
|
||||||
font-size: 100%;
|
font-size: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.addon-mod_bbb-recording-playback-title ion-label {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.addon-mod_bbb-recording-details {
|
.addon-mod_bbb-recording-details {
|
||||||
border-top: 2px solid var(--recording-details-border);
|
border-top: 2px solid var(--recording-details-border);
|
||||||
border-bottom: 2px solid var(--recording-details-border);
|
border-bottom: 2px solid var(--recording-details-border);
|
||||||
|
|
|
@ -25,7 +25,13 @@ import { CoreTextUtils } from '@services/utils/text';
|
||||||
import { CoreTimeUtils } from '@services/utils/time';
|
import { CoreTimeUtils } from '@services/utils/time';
|
||||||
import { CoreUtils } from '@services/utils/utils';
|
import { CoreUtils } from '@services/utils/utils';
|
||||||
import { Translate } from '@singletons';
|
import { Translate } from '@singletons';
|
||||||
import { AddonModBBB, AddonModBBBData, AddonModBBBMeetingInfo, AddonModBBBService } from '../../services/bigbluebuttonbn';
|
import {
|
||||||
|
AddonModBBB,
|
||||||
|
AddonModBBBData,
|
||||||
|
AddonModBBBMeetingInfo,
|
||||||
|
AddonModBBBRecordingPlaybackTypes,
|
||||||
|
AddonModBBBService,
|
||||||
|
} from '../../services/bigbluebuttonbn';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component that displays a Big Blue Button activity.
|
* Component that displays a Big Blue Button activity.
|
||||||
|
@ -43,7 +49,7 @@ export class AddonModBBBIndexComponent extends CoreCourseModuleMainActivityCompo
|
||||||
groupInfo?: CoreGroupInfo;
|
groupInfo?: CoreGroupInfo;
|
||||||
groupId = 0;
|
groupId = 0;
|
||||||
meetingInfo?: AddonModBBBMeetingInfo;
|
meetingInfo?: AddonModBBBMeetingInfo;
|
||||||
recordings?: RecordingData[];
|
recordings?: Recording[];
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
protected content?: IonContent,
|
protected content?: IonContent,
|
||||||
|
@ -139,13 +145,17 @@ export class AddonModBBBIndexComponent extends CoreCourseModuleMainActivityCompo
|
||||||
const columns = CoreUtils.arrayToObject(recordingsTable.columns, 'key');
|
const columns = CoreUtils.arrayToObject(recordingsTable.columns, 'key');
|
||||||
|
|
||||||
this.recordings = recordingsTable.parsedData.map(recordingData => {
|
this.recordings = recordingsTable.parsedData.map(recordingData => {
|
||||||
const playbackEl = CoreDomUtils.convertToElement(String(recordingData.playback));
|
const details: RecordingDetail[] = [];
|
||||||
const playbackAnchor = playbackEl.querySelector('a');
|
const playbacksEl = CoreDomUtils.convertToElement(String(recordingData.playback));
|
||||||
const details: RecordingDetailData[] = [];
|
const playbacks: RecordingPlayback[] = Array.from(playbacksEl.querySelectorAll('a')).map(playbackAnchor => ({
|
||||||
|
name: playbackAnchor.textContent ?? '',
|
||||||
|
url: playbackAnchor.href,
|
||||||
|
icon: this.getPlaybackIcon(playbackAnchor),
|
||||||
|
}));
|
||||||
|
|
||||||
Object.entries(recordingData).forEach(([key, value]) => {
|
Object.entries(recordingData).forEach(([key, value]) => {
|
||||||
const columnData = columns[key];
|
const columnData = columns[key];
|
||||||
if (!columnData || value === '' || key === 'actionbar') {
|
if (!columnData || value === '' || key === 'actionbar' || key === 'playback') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -158,10 +168,6 @@ export class AddonModBBBIndexComponent extends CoreCourseModuleMainActivityCompo
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (key === 'playback') {
|
|
||||||
// Remove HTML, we're only interested in the text.
|
|
||||||
value = (valueElement.textContent ?? '').trim();
|
|
||||||
} else {
|
|
||||||
// Treat "quick edit" buttons, they aren't supported in the app.
|
// Treat "quick edit" buttons, they aren't supported in the app.
|
||||||
const quickEditLink = valueElement.querySelector('.quickeditlink');
|
const quickEditLink = valueElement.querySelector('.quickeditlink');
|
||||||
if (quickEditLink) {
|
if (quickEditLink) {
|
||||||
|
@ -169,7 +175,6 @@ export class AddonModBBBIndexComponent extends CoreCourseModuleMainActivityCompo
|
||||||
value = (quickEditLink.querySelector('span')?.innerHTML ?? '').trim();
|
value = (quickEditLink.querySelector('span')?.innerHTML ?? '').trim();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
details.push({
|
details.push({
|
||||||
label: columnData.label,
|
label: columnData.label,
|
||||||
|
@ -179,16 +184,40 @@ export class AddonModBBBIndexComponent extends CoreCourseModuleMainActivityCompo
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
type: playbackAnchor?.innerText ??
|
|
||||||
Translate.instant('addon.mod_bigbluebuttonbn.view_recording_format_presentation'),
|
|
||||||
name: CoreTextUtils.cleanTags(String(recordingData.recording), { singleLine: true }),
|
name: CoreTextUtils.cleanTags(String(recordingData.recording), { singleLine: true }),
|
||||||
url: playbackAnchor?.href ?? '',
|
playbackLabel: columns.playback.label,
|
||||||
|
playbacks,
|
||||||
details,
|
details,
|
||||||
expanded: false,
|
expanded: false,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the playback icon.
|
||||||
|
*
|
||||||
|
* @param playbackAnchor Anchor element.
|
||||||
|
* @returns Icon name.
|
||||||
|
*/
|
||||||
|
protected getPlaybackIcon(playbackAnchor: HTMLAnchorElement): string {
|
||||||
|
const type = playbackAnchor.dataset.target;
|
||||||
|
switch (type) {
|
||||||
|
case AddonModBBBRecordingPlaybackTypes.NOTES:
|
||||||
|
return 'far-file-lines';
|
||||||
|
case AddonModBBBRecordingPlaybackTypes.PODCAST:
|
||||||
|
return 'fas-microphone-lines';
|
||||||
|
case AddonModBBBRecordingPlaybackTypes.SCREENSHARE:
|
||||||
|
return 'fas-display';
|
||||||
|
case AddonModBBBRecordingPlaybackTypes.STATISTICS:
|
||||||
|
return 'fas-chart-line';
|
||||||
|
case AddonModBBBRecordingPlaybackTypes.VIDEO:
|
||||||
|
return 'fas-video';
|
||||||
|
case AddonModBBBRecordingPlaybackTypes.PRESENTATION:
|
||||||
|
default:
|
||||||
|
return 'fas-circle-play';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritdoc
|
* @inheritdoc
|
||||||
*/
|
*/
|
||||||
|
@ -323,21 +352,21 @@ export class AddonModBBBIndexComponent extends CoreCourseModuleMainActivityCompo
|
||||||
*
|
*
|
||||||
* @param recording Recording.
|
* @param recording Recording.
|
||||||
*/
|
*/
|
||||||
toggle(recording: RecordingData): void {
|
toggle(recording: Recording): void {
|
||||||
recording.expanded = !recording.expanded;
|
recording.expanded = !recording.expanded;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Play a recording.
|
* Open a recording playback.
|
||||||
*
|
*
|
||||||
* @param event Click event.
|
* @param event Click event.
|
||||||
* @param recording Recording.
|
* @param playback Playback.
|
||||||
*/
|
*/
|
||||||
playRecording(event: MouseEvent, recording: RecordingData): void {
|
openPlayback(event: MouseEvent, playback: RecordingPlayback): void {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
|
|
||||||
CoreSites.getCurrentSite()?.openInBrowserWithAutoLogin(recording.url);
|
CoreSites.getCurrentSite()?.openInBrowserWithAutoLogin(playback.url);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -345,19 +374,28 @@ export class AddonModBBBIndexComponent extends CoreCourseModuleMainActivityCompo
|
||||||
/**
|
/**
|
||||||
* Recording data.
|
* Recording data.
|
||||||
*/
|
*/
|
||||||
type RecordingData = {
|
type Recording = {
|
||||||
type: string;
|
|
||||||
name: string;
|
name: string;
|
||||||
url: string;
|
|
||||||
expanded: boolean;
|
expanded: boolean;
|
||||||
details: RecordingDetailData[];
|
playbackLabel: string;
|
||||||
|
playbacks: RecordingPlayback[];
|
||||||
|
details: RecordingDetail[];
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Recording detail data.
|
* Recording detail data.
|
||||||
*/
|
*/
|
||||||
type RecordingDetailData = {
|
type RecordingDetail = {
|
||||||
label: string;
|
label: string;
|
||||||
value: string;
|
value: string;
|
||||||
allowHTML: boolean;
|
allowHTML: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recording playback data.
|
||||||
|
*/
|
||||||
|
type RecordingPlayback = {
|
||||||
|
name: string;
|
||||||
|
url: string;
|
||||||
|
icon: string;
|
||||||
|
};
|
||||||
|
|
|
@ -17,7 +17,5 @@
|
||||||
"view_message_viewer": "viewer",
|
"view_message_viewer": "viewer",
|
||||||
"view_message_viewers": "viewers",
|
"view_message_viewers": "viewers",
|
||||||
"view_nojoin": "You do not have a role that is allowed to join this session.",
|
"view_nojoin": "You do not have a role that is allowed to join this session.",
|
||||||
"view_recording_format_presentation": "Presentation",
|
|
||||||
"view_recording_list_action_play": "Play",
|
|
||||||
"view_section_title_recordings": "Recordings"
|
"view_section_title_recordings": "Recordings"
|
||||||
}
|
}
|
||||||
|
|
|
@ -548,3 +548,15 @@ export type AddonModBBBRecordingsWSTableData = {
|
||||||
export type AddonModBBBRecordingsTableData = AddonModBBBRecordingsWSTableData & {
|
export type AddonModBBBRecordingsTableData = AddonModBBBRecordingsWSTableData & {
|
||||||
parsedData: Record<string, string|number|boolean>[];
|
parsedData: Record<string, string|number|boolean>[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recording playback types.
|
||||||
|
*/
|
||||||
|
export enum AddonModBBBRecordingPlaybackTypes {
|
||||||
|
NOTES = 'notes',
|
||||||
|
PODCAST = 'podcast',
|
||||||
|
PRESENTATION = 'presentation',
|
||||||
|
SCREENSHARE = 'screenshare',
|
||||||
|
STATISTICS = 'statistics',
|
||||||
|
VIDEO = 'video',
|
||||||
|
}
|
||||||
|
|
|
@ -143,15 +143,15 @@ Feature: Test basic usage of BBB activity in app
|
||||||
| BBB | Recording 1 | Description 1 | 3 |
|
| BBB | Recording 1 | Description 1 | 3 |
|
||||||
| BBB | Recording 2 | Description 2 | 3 |
|
| BBB | Recording 2 | Description 2 | 3 |
|
||||||
And I entered the bigbluebuttonbn activity "BBB" on course "Course 1" as "student1" in the app
|
And I entered the bigbluebuttonbn activity "BBB" on course "Course 1" as "student1" in the app
|
||||||
Then I should find "Presentation" in the app
|
Then I should find "Recording 1" in the app
|
||||||
And I should find "Recording 1" in the app
|
|
||||||
And I should find "Recording 2" in the app
|
And I should find "Recording 2" in the app
|
||||||
But I should not find "Description 1" in the app
|
But I should not find "Description 1" in the app
|
||||||
And I should not find "Description 2" in the app
|
And I should not find "Description 2" in the app
|
||||||
|
And I should not find "Presentation" in the app
|
||||||
|
|
||||||
When I press "Recording 1" in the app
|
When I press "Recording 1" in the app
|
||||||
Then I should find "Description 1" in the app
|
Then I should find "Description 1" in the app
|
||||||
And I should find "Presentation" within "Playback" "ion-item" in the app
|
And I should find "Presentation" in the app
|
||||||
And I should find "Recording 1" within "Name" "ion-item" in the app
|
And I should find "Recording 1" within "Name" "ion-item" in the app
|
||||||
And I should find "Date" in the app
|
And I should find "Date" in the app
|
||||||
And I should find "3600" within "Duration" "ion-item" in the app
|
And I should find "3600" within "Duration" "ion-item" in the app
|
||||||
|
@ -162,12 +162,12 @@ Feature: Test basic usage of BBB activity in app
|
||||||
|
|
||||||
When I press "Recording 2" in the app
|
When I press "Recording 2" in the app
|
||||||
Then I should find "Description 2" in the app
|
Then I should find "Description 2" in the app
|
||||||
And I should find "Presentation" within "Playback" "ion-item" in the app
|
And I should find "Presentation" in the app
|
||||||
And I should find "Recording 2" within "Name" "ion-item" in the app
|
And I should find "Recording 2" within "Name" "ion-item" in the app
|
||||||
But I should not find "Description 1" in the app
|
But I should not find "Description 1" in the app
|
||||||
|
|
||||||
# Test play button, but the mock server doesn't support viewing recordings.
|
# Test play button, but the mock server doesn't support viewing recordings.
|
||||||
When I press "Play" near "Recording 1" in the app
|
When I press "Presentation" in the app
|
||||||
And I press "OK" in the app
|
And I press "OK" in the app
|
||||||
And I switch to the browser tab opened by the app
|
And I switch to the browser tab opened by the app
|
||||||
And I log in as "student1"
|
And I log in as "student1"
|
||||||
|
|
Loading…
Reference in New Issue