src/app/collection-detail-etb/collection-detail-etb.page.ts
OnInit
encapsulation | ViewEncapsulation.None |
selector | app-collection-detail-etb |
styleUrls | ./collection-detail-etb.page.scss |
templateUrl | ./collection-detail-etb.page.html |
constructor(contentService: ContentService, eventBusService: EventsBusService, profileService: ProfileService, storageService: StorageService, downloadService: DownloadService, zone: NgZone, events: Events, popoverCtrl: PopoverController, platform: Platform, appGlobalService: AppGlobalService, commonUtilService: CommonUtilService, navService: NavigationService, telemetryGeneratorService: TelemetryGeneratorService, fileSizePipe: FileSizePipe, headerService: AppHeaderService, location: Location, router: Router, changeDetectionRef: ChangeDetectorRef, textbookTocService: TextbookTocService, contentPlayerHandler: ContentPlayerHandler, contentDeleteHandler: ContentDeleteHandler, sbProgressLoader: SbProgressLoader)
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Parameters :
|
Private assignCardData |
assignCardData()
|
Returns :
void
|
cancelDownload |
cancelDownload()
|
Returns :
void
|
changeValue | ||||
changeValue(text)
|
||||
Parameters :
Returns :
void
|
contentInfo |
contentInfo()
|
Returns :
void
|
downloadAllContent |
downloadAllContent()
|
Download single content
Returns :
void
|
extractApiResponse | ||||||
extractApiResponse(data: Content)
|
||||||
Function to extract api response.
Parameters :
Returns :
void
|
generateCancelDownloadTelemetry |
generateCancelDownloadTelemetry()
|
Returns :
void
|
generateEndEvent | ||||||||
generateEndEvent(objectId, objectType, objectVersion)
|
||||||||
Parameters :
Returns :
void
|
generateImpressionEvent | ||||||||
generateImpressionEvent(objectId, objectType, objectVersion)
|
||||||||
Parameters :
Returns :
void
|
generateQRSessionEndEvent |
generateQRSessionEndEvent(pageId: string, qrData: string)
|
Returns :
void
|
generateStartEvent | ||||||||
generateStartEvent(objectId, objectType, objectVersion)
|
||||||||
Parameters :
Returns :
void
|
getContentsSize | ||||
getContentsSize(data)
|
||||
Parameters :
Returns :
void
|
getImportContentRequestBody | ||||||||||||
getImportContentRequestBody(identifiers: Array
|
||||||||||||
Function to get import content api request params
Parameters :
Returns :
Array<ContentImport>
|
handleBackButton |
handleBackButton()
|
Returns :
void
|
handleHeaderEvents | ||||
handleHeaderEvents($event)
|
||||
Parameters :
Returns :
void
|
importContent | ||||||||||||||||
importContent(identifiers: Array
|
||||||||||||||||
Function to get import content api request params
Parameters :
Returns :
void
|
importContentInBackground | |||||||||
importContentInBackground(identifiers: Array
|
|||||||||
Parameters :
Returns :
void
|
ionViewDidEnter |
ionViewDidEnter()
|
Returns :
void
|
ionViewWillEnter |
ionViewWillEnter()
|
Returns :
void
|
ionViewWillLeave |
ionViewWillLeave()
|
Ionic life cycle hook
Returns :
void
|
isGroupShown | ||||
isGroupShown(group)
|
||||
Parameters :
Returns :
boolean
|
markContent |
markContent()
|
Returns :
void
|
mergeProperties | ||||
mergeProperties(mergeProp)
|
||||
Parameters :
Returns :
any
|
navigateToDetailsPage | ||||||||||||
navigateToDetailsPage(content: any, depth, corRelationData?)
|
||||||||||||
Parameters :
Returns :
void
|
ngOnInit |
ngOnInit()
|
Returns :
void
|
Async onFilterMimeTypeChange | ||||||||
onFilterMimeTypeChange(val, idx, currentFilter?)
|
||||||||
Parameters :
Returns :
any
|
onScroll | ||||
onScroll(event)
|
||||
Parameters :
Returns :
void
|
openBrowser | ||||
openBrowser(url)
|
||||
Parameters :
Returns :
void
|
openTextbookToc |
openTextbookToc()
|
Returns :
void
|
playButtonClick | ||||
playButtonClick(event)
|
||||
Parameters :
Returns :
void
|
playContent | ||||||
playContent(event, corRelationData?)
|
||||||
Parameters :
Returns :
void
|
Private redirectToActivedownloads |
redirectToActivedownloads()
|
Returns :
void
|
refreshContentDetails | ||||
refreshContentDetails(data)
|
||||
Parameters :
Returns :
void
|
refreshHeader |
refreshHeader()
|
Returns :
void
|
registerDeviceBackButton |
registerDeviceBackButton()
|
Returns :
void
|
resetVariables |
resetVariables()
|
Reset all values
Returns :
void
|
Private setActiveContentData | ||||||||
setActiveContentData(event, telemetrySubType, corRelationData)
|
||||||||
Parameters :
Returns :
void
|
setChildContents |
setChildContents()
|
Function to set child contents
Returns :
void
|
setCollectionStructure |
setCollectionStructure()
|
Returns :
void
|
Async setContentDetails | ||||||||||||
setContentDetails(identifier, refreshContentDetails: boolean)
|
||||||||||||
To set content details in local variable
Parameters :
Returns :
any
|
Private setExtrasData | ||||
setExtrasData(extras)
|
||||
Parameters :
Returns :
void
|
Private setTocData | ||||
setTocData(content)
|
||||
Parameters :
Returns :
void
|
Async share |
share()
|
Returns :
any
|
Async showDeletePopOver |
showDeletePopOver()
|
Returns :
any
|
Async showDownloadConfirmationAlert |
showDownloadConfirmationAlert()
|
Returns :
any
|
subscribeSdkEvent |
subscribeSdkEvent()
|
Subscribe Sunbird-SDK event to get content download progress
Returns :
void
|
tocCardClick | ||||
tocCardClick(event)
|
||||
Parameters :
Returns :
void
|
toggleGroup | ||||||||
toggleGroup(group, content, openCarousel?)
|
||||||||
Parameters :
Returns :
void
|
updateSavedResources |
updateSavedResources()
|
Returns :
void
|
_licenseDetails |
Type : any
|
accordianConfig |
Type : IAccordianConfig
|
Default value : {
expandMode: ExpandMode.SINGLE,
expandBehavior: ExpandBehavior.EXPAND_FIRST
}
|
activeContent |
activeMimeTypeFilter |
Type : []
|
Default value : ['all']
|
appName |
Type : any
|
Public backButtonFunc |
Type : Subscription
|
Public baseUrl |
Type : string
|
Default value : ''
|
batchDetails |
Type : any
|
breadCrumb |
Default value : new Map()
|
cardData |
Type : any
|
Contains card data of previous state |
Optional childrenData |
Type : Array<any>
|
collectionChildComp |
Type : CollectionChildComponent
|
Decorators :
@ViewChild('collectionChildComp', {static: false})
|
collectionTocData |
Type : Content
|
content |
Type : any
|
contentDeleteObservable |
Type : any
|
Optional contentDetail |
Type : Content
|
contentId |
Type : string
|
contentTypesCount |
Type : any
|
Public corRelationList |
Type : Array<CorrelationData>
|
currentCount |
Type : number
|
Default value : 0
|
Current download count |
currentFilter |
Type : string
|
Default value : 'ALL'
|
data |
Type : any
|
defaultAppIcon |
Type : string
|
depth |
Type : string
|
Default value : '1'
|
Contains current course depth |
Public didViewLoad |
Type : boolean
|
downloadContentsSize |
Type : string
|
Contains total size of locally not available content(s) |
downloadIdentifiers |
Type : Set<string>
|
Default value : new Set()
|
Contains identifier(s) of locally not available content(s) |
downloadPercentage |
Type : number
|
downloadProgress |
Type : any
|
Contains child content import / download progress |
downloadSize |
Type : number
|
Default value : 0
|
Child content size |
Private eventSubscription |
Type : Subscription
|
facets |
Type : any
|
faultyIdentifiers |
Type : Array<any>
|
Default value : []
|
fromCoursesPage |
Default value : false
|
sets true , if it comes from courses |
headerConfig |
Type : object
|
Default value : {
showHeader: true,
showBurgerMenu: false,
actionButtons: []
}
|
headerObservable |
Type : any
|
hiddenGroups |
Default value : new Set()
|
identifier |
Type : string
|
To hold identifier |
importProgressMessage |
Type : string
|
ionContent |
Type : iContent
|
Decorators :
@ViewChild(iContent, {static: false})
|
isAlreadyEnrolled |
Default value : false
|
isChapterVisible |
Default value : false
|
isChild |
Default value : false
|
isChildClickable |
Default value : false
|
isContentPlayed |
Default value : false
|
isDepthChild |
Default value : false
|
Its get true when child is collection. Used to show content depth
|
isDownloadCompleted |
Default value : false
|
Download complete falg |
isDownloadStarted |
Default value : false
|
Flag downlaoded started |
isSelected |
Type : boolean
|
isUpdateAvailable |
Default value : false
|
Needed to handle collection auto update workflow |
localImage |
Type : string
|
Default value : ''
|
localResourseCount |
Type : number
|
objectKeys |
Default value : Object.keys
|
To get course structure keys |
objId |
Public objRollup |
Type : Rollup
|
Telemetry roll up object |
objType |
objVer |
pageId |
Type : string
|
Default value : PageId.COLLECTION_DETAIL
|
pageName |
Type : any
|
parentContent |
Type : any
|
Contains Parent Content Details |
playBtnConfig |
Type : IButtonConfig
|
Private Optional previousHeaderBottomOffset |
Type : number
|
queuedIdentifiers |
Type : Array<any>
|
Default value : []
|
To hold content identifiers |
ratingComment |
Type : string
|
Default value : ''
|
Rating comment |
Public rollUpMap |
Type : literal type
|
Default value : {}
|
scrollPosition |
Type : number
|
Default value : 0
|
selected |
Type : boolean
|
Public shouldGenerateEndTelemetry |
Default value : false
|
shouldPillsStick |
Default value : false
|
showChildrenLoader |
Type : boolean
|
Show loader while importing content |
showCollapsedPopup |
Default value : true
|
showContentDetails |
Default value : false
|
showCredits |
Default value : false
|
showDownload |
Type : boolean
|
showDownloadBtn |
Default value : false
|
Contains |
Public showLoading |
Default value : false
|
shownGroups |
Default value : undefined
|
showSheenAnimation |
Default value : true
|
Public source |
Type : string
|
Default value : ''
|
stateData |
Type : any
|
Optional stckyUnitTitle |
Type : string
|
stickyPillsRef |
Type : ElementRef
|
Decorators :
@ViewChild('stickyPillsRef', {static: false})
|
Public telemetryObject |
Type : TelemetryObject
|
TocCardType |
Default value : TocCardType
|
totalDownload |
Type : number
|
Total download count |
trackDownloads$ |
Type : Observable<DownloadTracking>
|
userRating |
Type : number
|
Default value : 0
|
To hold rating data |
licenseDetails | ||||
getlicenseDetails()
|
||||
setlicenseDetails(val)
|
||||
Parameters :
Returns :
void
|
import { Location } from '@angular/common';
import {
ChangeDetectorRef,
Component,
ElementRef,
Inject,
NgZone,
OnInit,
ViewChild,
ViewEncapsulation
} from '@angular/core';
import { Router } from '@angular/router';
import { FileSizePipe } from '@app/pipes/file-size/file-size';
import { ContentDeleteHandler } from '@app/services/content/content-delete-handler';
import { ContentInfo } from '@app/services/content/content-info';
import { ContentPlayerHandler } from '@app/services/content/player/content-player-handler';
import { NavigationService } from '@app/services/navigation-handler.service';
import { ContentUtil } from '@app/util/content-util';
import { IonContent as iContent, Platform, PopoverController } from '@ionic/angular';
import { Events } from '@app/util/events';
import { CsPrimaryCategory } from '@project-sunbird/client-services/services/content';
import { ExpandBehavior, ExpandMode, IAccordianConfig, IButtonConfig, TocCardType } from '@project-sunbird/common-consumption';
import isObject from 'lodash/isObject';
import { Observable, Subscription } from 'rxjs';
import { share } from 'rxjs/operators';
import {
Content,
ContentAccess,
ContentAccessStatus,
ContentDetailRequest,
ContentEventType,
ContentImport,
ContentImportCompleted,
ContentImportRequest,
ContentImportResponse,
ContentImportStatus,
ContentMarkerRequest,
ContentService,
ContentUpdate,
CorrelationData,
DownloadEventType,
DownloadProgress,
DownloadService,
DownloadTracking,
EventsBusEvent,
EventsBusService,
MarkerType,
Profile,
ProfileService,
Rollup,
StorageService,
TelemetryErrorCode,
TelemetryObject
} from 'sunbird-sdk';
import { EventTopics, RouterLinks, ShareItemType } from '../../app/app.constant';
import {
AppGlobalService, AppHeaderService, CommonUtilService,
TelemetryGeneratorService
} from '../../services';
import { SbProgressLoader } from '../../services/sb-progress-loader.service';
import { CorReleationDataType, Environment, ErrorType, ImpressionType, InteractSubtype, InteractType, Mode, PageId } from '../../services/telemetry-constants';
import { CollectionChildComponent, ConfirmAlertComponent } from '../components';
import { SbSharePopupComponent } from '../components/popups/sb-share-popup/sb-share-popup.component';
import { TextbookTocService } from './textbook-toc-service';
import { TagPrefixConstants } from '@app/services/segmentation-tag/segmentation-tag.service';
@Component({
selector: 'app-collection-detail-etb',
templateUrl: './collection-detail-etb.page.html',
styleUrls: ['./collection-detail-etb.page.scss'],
encapsulation: ViewEncapsulation.None,
})
export class CollectionDetailEtbPage implements OnInit {
facets: any;
selected: boolean;
isSelected: boolean;
headerConfig = {
showHeader: true,
showBurgerMenu: false,
actionButtons: []
};
contentDetail?: Content;
childrenData?: Array<any>;
mimeTypes = [
{ name: 'ALL', selected: true, value: ['all'], iconNormal: '', iconActive: '' },
{
name: 'VIDEO', value: ['video/mp4', 'video/x-youtube', 'video/webm'], iconNormal: './assets/imgs/play.svg',
iconActive: './assets/imgs/play-active.svg'
},
{
name: 'DOC', value: ['application/pdf', 'application/epub', 'application/msword'], iconNormal: './assets/imgs/doc.svg',
iconActive: './assets/imgs/doc-active.svg'
},
{
name: 'INTERACTION',
value: ['application/vnd.ekstep.ecml-archive', 'application/vnd.ekstep.h5p-archive', 'application/vnd.ekstep.html-archive'],
iconNormal: './assets/imgs/touch.svg', iconActive: './assets/imgs/touch-active.svg'
},
// { name: 'AUDIOS', value: MimeType.AUDIO, iconNormal: './assets/imgs/audio.svg', iconActive: './assets/imgs/audio-active.svg'},
];
activeMimeTypeFilter = ['all'];
/**
* Show loader while importing content
*/
showChildrenLoader: boolean;
/**
* Contains card data of previous state
*/
cardData: any;
/**
* Contains Parent Content Details
*/
parentContent: any;
/**
* To hold identifier
*/
identifier: string;
/**
* Contains child content import / download progress
*/
downloadProgress: any;
/**
* To get course structure keys
*/
objectKeys = Object.keys;
/**
* Contains
*/
showDownloadBtn = false;
/**
* Flag downlaoded started
*/
isDownloadStarted = false;
/**
* Contains current course depth
*/
depth = '1';
/**
* Its get true when child is collection.
* Used to show content depth
*
* @example 1.1 Collection 1
*/
isDepthChild = false;
/**
* To hold content identifiers
*/
queuedIdentifiers: Array<any> = [];
faultyIdentifiers: Array<any> = [];
/**
* Download complete falg
*/
isDownloadCompleted = false;
/**
* Total download count
*/
totalDownload: number;
/**
* Current download count
*/
currentCount = 0;
/**
* Contains identifier(s) of locally not available content(s)
*/
downloadIdentifiers: Set<string> = new Set();
/**
* Child content size
*/
downloadSize = 0;
showCredits = false;
/**
* Contains total size of locally not available content(s)
*/
downloadContentsSize: string;
downloadPercentage: number;
objId;
objType;
objVer;
public showLoading = false;
/**
* Needed to handle collection auto update workflow
*/
isUpdateAvailable = false;
/**
* To hold rating data
*/
userRating = 0;
isAlreadyEnrolled = false;
/** sets true , if it comes from courses */
fromCoursesPage = false;
/**
* Rating comment
*/
ratingComment = '';
// defaultIcon
defaultAppIcon: string;
localResourseCount: number;
/**
* Telemetry roll up object
*/
public objRollup: Rollup;
public didViewLoad: boolean;
public backButtonFunc: Subscription;
public baseUrl = '';
public corRelationList: Array<CorrelationData>;
public shouldGenerateEndTelemetry = false;
public source = '';
isChildClickable = false;
hiddenGroups = new Set();
shownGroups = undefined;
content: any;
data: any;
isChild = false;
contentId: string;
batchDetails: any;
pageName: any;
headerObservable: any;
breadCrumb = new Map();
scrollPosition = 0;
currentFilter = 'ALL';
localImage = '';
appName: any;
@ViewChild(iContent, { static: false }) ionContent: iContent;
@ViewChild('stickyPillsRef', { static: false }) stickyPillsRef: ElementRef;
@ViewChild('collectionChildComp', { static: false }) collectionChildComp: CollectionChildComponent;
private eventSubscription: Subscription;
showDownload: boolean;
contentTypesCount: any;
stateData: any;
stckyUnitTitle?: string;
isChapterVisible = false;
shouldPillsStick = false;
importProgressMessage: string;
showSheenAnimation = true;
public telemetryObject: TelemetryObject;
public rollUpMap: { [key: string]: Rollup } = {};
private previousHeaderBottomOffset?: number;
isContentPlayed = false;
contentDeleteObservable: any;
_licenseDetails: any;
trackDownloads$: Observable<DownloadTracking>;
showCollapsedPopup = true;
get licenseDetails() {
return this._licenseDetails;
}
set licenseDetails(val) {
if (!this._licenseDetails && val) {
this._licenseDetails = val;
}
}
pageId: string = PageId.COLLECTION_DETAIL;
collectionTocData: Content;
TocCardType = TocCardType;
activeContent;
playBtnConfig: IButtonConfig;
accordianConfig: IAccordianConfig = {
expandMode: ExpandMode.SINGLE,
expandBehavior: ExpandBehavior.EXPAND_FIRST
};
showContentDetails = false;
constructor(
@Inject('CONTENT_SERVICE') private contentService: ContentService,
@Inject('EVENTS_BUS_SERVICE') private eventBusService: EventsBusService,
@Inject('PROFILE_SERVICE') private profileService: ProfileService,
@Inject('STORAGE_SERVICE') private storageService: StorageService,
@Inject('DOWNLOAD_SERVICE') private downloadService: DownloadService,
private zone: NgZone,
private events: Events,
private popoverCtrl: PopoverController,
private platform: Platform,
private appGlobalService: AppGlobalService,
private commonUtilService: CommonUtilService,
private navService: NavigationService,
private telemetryGeneratorService: TelemetryGeneratorService,
private fileSizePipe: FileSizePipe,
private headerService: AppHeaderService,
private location: Location,
private router: Router,
private changeDetectionRef: ChangeDetectorRef,
private textbookTocService: TextbookTocService,
private contentPlayerHandler: ContentPlayerHandler,
private contentDeleteHandler: ContentDeleteHandler,
private sbProgressLoader: SbProgressLoader
) {
this.objRollup = new Rollup();
this.defaultAppIcon = 'assets/imgs/ic_launcher.png';
const extras = this.router.getCurrentNavigation().extras.state;
if (extras) {
this.setExtrasData(extras);
}
}
private setExtrasData(extras) {
this.content = extras.content;
this.data = extras.data;
this.cardData = extras.content;
this.batchDetails = extras.batchDetails;
this.pageName = extras.pageName;
this.depth = extras.depth;
this.corRelationList = extras.corRelation || [];
this.shouldGenerateEndTelemetry = extras.shouldGenerateEndTelemetry;
this.source = extras.source;
this.fromCoursesPage = extras.fromCoursesPage;
this.isAlreadyEnrolled = extras.isAlreadyEnrolled;
this.isChildClickable = extras.isChildClickable;
this.facets = extras.facets;
this.telemetryObject = ContentUtil.getTelemetryObject(extras.content);
this.parentContent = extras.parentContent;
if (this.depth) {
this.showDownloadBtn = false;
this.isDepthChild = true;
} else {
this.isDepthChild = false;
}
this.pageId = this.commonUtilService.appendTypeToPrimaryCategory(this.content) || this.pageId;
this.identifier = this.cardData.contentId || this.cardData.identifier;
window['segmentation'].SBTagService.pushTag(
window['segmentation'].SBTagService.getTags(TagPrefixConstants.CONTENT_ID) ? this.identifier : [this.identifier],
TagPrefixConstants.CONTENT_ID,
window['segmentation'].SBTagService.getTags(TagPrefixConstants.CONTENT_ID) ? false : true
);
}
ngOnInit() {
this.playBtnConfig = {
label: this.commonUtilService.translateMessage('PLAY'),
show: true
};
this.commonUtilService.getAppName().then((res) => { this.appName = res; });
window['scrollWindow'] = this.ionContent;
this.trackDownloads$ = this.downloadService.trackDownloads({ groupBy: { fieldPath: 'rollUp.l1', value: this.identifier } }).pipe(
share());
}
ionViewWillEnter() {
this.headerService.showStatusBar();
this.registerDeviceBackButton();
this.zone.run(() => {
this.headerObservable = this.headerService.headerEventEmitted$.subscribe(eventName => {
this.handleHeaderEvents(eventName);
});
this.headerConfig = this.headerService.getDefaultPageConfig();
this.headerConfig.actionButtons = ['download'];
this.headerConfig.showHeader = false;
this.headerConfig.showBurgerMenu = false;
this.headerService.updatePageConfig(this.headerConfig);
this.hiddenGroups.clear();
this.shownGroups = undefined;
this.assignCardData();
this.resetVariables();
this.setContentDetails(this.identifier, true);
this.events.subscribe(EventTopics.CONTENT_TO_PLAY, (data) => {
this.playContent(data);
});
this.subscribeSdkEvent();
});
this.ionContent.ionScroll.subscribe((event) => {
this.scrollPosition = event.scrollTop;
});
this.events.subscribe(EventTopics.DEEPLINK_COLLECTION_PAGE_OPEN, (data) => {
if (data.content) {
this.refreshContentDetails(data);
}
});
this.events.subscribe(EventTopics.NEXT_CONTENT, async (data) => {
console.log('Next Content', data);
this.content = data.content;
this.playContent(data);
setTimeout(() => {
this.contentPlayerHandler.setLastPlayedContentId('');
}, 1000);
});
}
ionViewDidEnter() {
this.sbProgressLoader.hide({ id: this.identifier });
}
private assignCardData() {
if (!this.didViewLoad) {
this.objRollup = ContentUtil.generateRollUp(this.cardData.hierarchyInfo, this.cardData.identifier);
const contentType = this.cardData.contentData ? this.cardData.contentData.contentType : this.cardData.contentType;
this.objType = contentType;
this.generateStartEvent(this.cardData.identifier, contentType, this.cardData.pkgVersion);
this.generateImpressionEvent(this.cardData.identifier, contentType, this.cardData.pkgVersion);
this.markContent();
}
this.didViewLoad = true;
}
refreshContentDetails(data) {
this.resetVariables();
this.shownGroups = undefined;
this.hiddenGroups.clear();
this.setExtrasData(data);
this.didViewLoad = false;
this.assignCardData();
this.setContentDetails(this.identifier, true);
this.subscribeSdkEvent();
}
openBrowser(url) {
this.commonUtilService.openUrlInBrowser(url);
}
markContent() {
const addContentAccessRequest: ContentAccess = {
status: ContentAccessStatus.PLAYED,
contentId: this.identifier,
contentType: this.content.contentType
};
const profile: Profile = this.appGlobalService.getCurrentUser();
this.profileService.addContentAccess(addContentAccessRequest).toPromise().then((data) => {
if (data) {
this.events.publish(EventTopics.LAST_ACCESS_ON, true);
}
});
const contentMarkerRequest: ContentMarkerRequest = {
uid: profile.uid,
contentId: this.identifier,
data: JSON.stringify(this.content.contentData),
marker: MarkerType.PREVIEWED,
isMarked: true,
extraInfo: {}
};
this.contentService.setContentMarker(contentMarkerRequest).toPromise().then();
}
// toggle the card
toggleGroup(group, content, openCarousel?) {
let isCollapsed = true;
if (!openCarousel && this.isGroupShown(group)) {
isCollapsed = false;
this.shownGroups = undefined;
this.hiddenGroups.add(group);
} else {
isCollapsed = false;
this.shownGroups = group;
this.hiddenGroups.delete(group);
}
const values = new Map();
values['isCollapsed'] = isCollapsed;
this.telemetryGeneratorService.generateInteractTelemetry(
InteractType.TOUCH,
InteractSubtype.UNIT_CLICKED,
Environment.HOME,
PageId.COLLECTION_DETAIL,
this.telemetryObject,
values,
this.objRollup,
this.corRelationList
);
this.telemetryGeneratorService.generateInteractTelemetry(
InteractType.TOUCH,
InteractSubtype.UNIT_CLICKED,
Environment.HOME,
this.pageId,
this.telemetryObject,
values,
this.objRollup,
this.corRelationList
);
}
// to check whether the card is toggled or not
isGroupShown(group) {
if (this.activeMimeTypeFilter.indexOf('all') === 0) {
return this.shownGroups === group;
} else {
return !this.hiddenGroups.has(group);
}
}
changeValue(text) {
if (!text) {
this.isSelected = false;
} else {
this.isSelected = true;
}
}
handleBackButton() {
this.didViewLoad = false;
this.generateEndEvent(this.objId, this.objType, this.objVer);
if (this.shouldGenerateEndTelemetry) {
this.generateQRSessionEndEvent(this.source, this.cardData.identifier);
}
if (this.source === PageId.ONBOARDING_PROFILE_PREFERENCES) {
this.router.navigate([`/${RouterLinks.PROFILE_SETTINGS}`], { state: { showFrameworkCategoriesMenu: true }, replaceUrl: true });
} else {
this.location.back();
}
}
registerDeviceBackButton() {
this.backButtonFunc = this.platform.backButton.subscribeWithPriority(10, () => {
this.telemetryGeneratorService.generateBackClickedTelemetry(PageId.COLLECTION_DETAIL, Environment.HOME,
false, this.cardData.identifier, this.corRelationList);
this.telemetryGeneratorService.generateBackClickedTelemetry(this.pageId, Environment.HOME,
false, this.cardData.identifier, this.corRelationList);
this.handleBackButton();
});
}
/**
* To set content details in local variable
* @param identifier identifier of content / course
*/
async setContentDetails(identifier, refreshContentDetails: boolean) {
const option: ContentDetailRequest = {
contentId: identifier,
objectType: this.cardData.objectType,
attachFeedback: true,
attachContentAccess: true,
emitUpdateIfAny: refreshContentDetails
};
this.contentService.getContentDetails(option).toPromise()
.then((data: Content | any) => {
if (data) {
this.licenseDetails = data.contentData.licenseDetails || this.licenseDetails;
if (data.contentData.attributions && data.contentData.attributions.length) {
data.contentData.attributions = (data.contentData.attributions.sort()).join(', ');
}
if (!data.isAvailableLocally) {
this.contentDetail = data;
this.telemetryGeneratorService.generatefastLoadingTelemetry(
InteractSubtype.FAST_LOADING_INITIATED,
PageId.COLLECTION_DETAIL,
this.telemetryObject,
undefined,
this.objRollup,
this.corRelationList
);
this.telemetryGeneratorService.generatefastLoadingTelemetry(
InteractSubtype.FAST_LOADING_INITIATED,
this.pageId,
this.telemetryObject,
undefined,
this.objRollup,
this.corRelationList
);
this.contentService.getContentHeirarchy(option).toPromise()
.then((content: Content) => {
this.setTocData(content);
this.showSheenAnimation = false;
this.toggleGroup(0, this.content);
this.telemetryGeneratorService.generatefastLoadingTelemetry(
InteractSubtype.FAST_LOADING_FINISHED,
PageId.COLLECTION_DETAIL,
this.telemetryObject,
undefined,
this.objRollup,
this.corRelationList
);
this.telemetryGeneratorService.generatefastLoadingTelemetry(
InteractSubtype.FAST_LOADING_FINISHED,
this.pageId,
this.telemetryObject,
undefined,
this.objRollup,
this.corRelationList
);
}).catch(() => {
this.showSheenAnimation = false;
});
this.importContentInBackground([this.identifier], false);
} else {
this.showSheenAnimation = false;
this.extractApiResponse(data);
}
}
}).catch((error) => {
console.log('error while loading content details', error);
this.showSheenAnimation = false;
this.commonUtilService.showToast('ERROR_CONTENT_NOT_AVAILABLE');
this.location.back();
});
}
/**
* Function to extract api response.
*/
extractApiResponse(data: Content) {
this.contentDetail = data;
this.contentDetail.contentData.appIcon = ContentUtil.getAppIcon(this.contentDetail.contentData.appIcon,
this.contentDetail.basePath, this.commonUtilService.networkInfo.isNetworkAvailable);
this.objId = this.contentDetail.identifier;
this.objVer = this.contentDetail.contentData.pkgVersion;
// User Rating
const contentFeedback: any = data.contentFeedback ? data.contentFeedback : [];
if (contentFeedback !== undefined && contentFeedback.length !== 0) {
this.userRating = contentFeedback[0].rating;
this.ratingComment = contentFeedback[0].comments;
}
if (Boolean(data.isAvailableLocally)) {
this.showLoading = false;
this.refreshHeader();
if (data.isUpdateAvailable && !this.isUpdateAvailable) {
this.isUpdateAvailable = true;
this.showLoading = true;
this.telemetryGeneratorService.generateSpineLoadingTelemetry(this.contentDetail, false);
this.importContent([this.identifier], false);
} else {
this.isUpdateAvailable = false;
this.setChildContents();
}
} else {
this.showLoading = true;
this.telemetryGeneratorService.generateSpineLoadingTelemetry(this.contentDetail, true);
this.importContent([this.identifier], false);
}
if (this.contentDetail.contentData.me_totalDownloads) {
this.contentDetail.contentData.me_totalDownloads = this.contentDetail.contentData.me_totalDownloads.split('.')[0];
}
this.setCollectionStructure();
}
setCollectionStructure() {
this.showChildrenLoader = true;
if (this.contentDetail.contentData.contentTypesCount) {
if (!isObject(this.contentDetail.contentData.contentTypesCount)) {
this.contentTypesCount = JSON.parse(this.contentDetail.contentData.contentTypesCount);
} else {
this.contentTypesCount = this.contentDetail.contentData.contentTypesCount;
}
} else if (this.cardData.contentTypesCount) {
if (!isObject(this.cardData.contentTypesCount)) {
this.contentTypesCount = JSON.parse(this.cardData.contentTypesCount);
}
}
}
/**
* Function to get import content api request params
*
* @param identifiers contains list of content identifier(s)
*/
getImportContentRequestBody(identifiers: Array<string>, isChild: boolean): Array<ContentImport> {
const requestParams: ContentImport[] = [];
const folderPath = this.platform.is('ios') ? cordova.file.documentsDirectory : this.storageService.getStorageDestinationDirectoryPath();
identifiers.forEach((value) => {
requestParams.push({
isChildContent: isChild,
destinationFolder: folderPath,
contentId: value,
correlationData: this.corRelationList ? this.corRelationList : [],
rollUp: this.rollUpMap[value]
});
});
return requestParams;
}
/**
* Function to get import content api request params
*
* @param identifiers contains list of content identifier(s)
*/
importContent(identifiers: Array<string>, isChild: boolean, isDownloadAllClicked?) {
if (this.showLoading && !this.isDownloadStarted) {
this.headerService.hideHeader();
}
const option: ContentImportRequest = {
contentImportArray: this.getImportContentRequestBody(identifiers, isChild),
contentStatusArray: ['Live'],
fields: ['appIcon', 'name', 'subject', 'size', 'gradeLevel'],
};
// Call content service
this.contentService.importContent(option).toPromise()
.then((data: ContentImportResponse[]) => {
this.zone.run(() => {
if (data && data.length && this.isDownloadStarted) {
data.forEach((value) => {
if (value.status === ContentImportStatus.ENQUEUED_FOR_DOWNLOAD) {
this.queuedIdentifiers.push(value.identifier);
} else if (value.status === ContentImportStatus.NOT_FOUND) {
this.faultyIdentifiers.push(value.identifier);
}
});
if (isDownloadAllClicked) {
this.telemetryGeneratorService.generateDownloadAllClickTelemetry(
PageId.COLLECTION_DETAIL,
this.contentDetail,
this.queuedIdentifiers,
identifiers.length
);
this.telemetryGeneratorService.generateDownloadAllClickTelemetry(
this.pageId,
this.contentDetail,
this.queuedIdentifiers,
identifiers.length
);
}
if (this.queuedIdentifiers.length === 0) {
if (this.isDownloadStarted) {
this.showDownloadBtn = true;
this.isDownloadStarted = false;
this.showLoading = false;
this.refreshHeader();
}
}
if (this.faultyIdentifiers.length > 0) {
const stackTrace: any = {};
stackTrace.parentIdentifier = this.cardData.identifier;
stackTrace.faultyIdentifiers = this.faultyIdentifiers;
this.telemetryGeneratorService.generateErrorTelemetry(Environment.HOME,
TelemetryErrorCode.ERR_DOWNLOAD_FAILED,
ErrorType.SYSTEM,
PageId.COLLECTION_DETAIL,
JSON.stringify(stackTrace),
);
this.telemetryGeneratorService.generateErrorTelemetry(Environment.HOME,
TelemetryErrorCode.ERR_DOWNLOAD_FAILED,
ErrorType.SYSTEM,
this.pageId,
JSON.stringify(stackTrace),
);
this.commonUtilService.showToast('UNABLE_TO_FETCH_CONTENT');
}
} else if (data && data[0].status === ContentImportStatus.NOT_FOUND) {
this.showLoading = false;
this.refreshHeader();
this.showChildrenLoader = false;
this.childrenData.length = 0;
this.collectionTocData.children.length = 0;
}
});
})
.catch((error: any) => {
this.zone.run(() => {
this.showDownloadBtn = true;
this.isDownloadStarted = false;
this.showLoading = false;
this.refreshHeader();
if (Boolean(this.isUpdateAvailable)) {
this.setChildContents();
} else {
if (error && (error.error === 'NETWORK_ERROR' || error.error === 'CONNECTION_ERROR')) {
this.commonUtilService.showToast('NEED_INTERNET_TO_CHANGE');
} else {
this.commonUtilService.showToast('UNABLE_TO_FETCH_CONTENT');
}
this.showChildrenLoader = false;
this.location.back();
}
});
});
}
/**
* Function to set child contents
*/
setChildContents() {
this.showChildrenLoader = true;
const hierarchyInfo = this.cardData.hierarchyInfo ? this.cardData.hierarchyInfo : null;
const option = { contentId: this.identifier, hierarchyInfo };
this.contentService.getChildContents(option).toPromise()
.then((data: Content) => {
this.zone.run(() => {
if (data && data.children) {
this.breadCrumb.set(data.identifier, data.contentData.name);
if (this.textbookTocService.textbookIds.rootUnitId && this.activeMimeTypeFilter !== ['all']) {
this.onFilterMimeTypeChange(this.mimeTypes[0].value, 0, this.mimeTypes[0].name);
}
if (this.textbookTocService.textbookIds.content) {
this.activeContent = this.textbookTocService.textbookIds.content;
}
this.setTocData(data);
this.changeDetectionRef.detectChanges();
}
if (!this.isDepthChild) {
this.downloadSize = 0;
this.localResourseCount = 0;
this.getContentsSize(data.children || []);
}
this.showChildrenLoader = false;
if (this.textbookTocService.textbookIds.contentId) {
setTimeout(() => {
(this.stickyPillsRef.nativeElement as HTMLDivElement).classList.add('sticky');
window['scrollWindow'].getScrollElement().then(() => {
document.getElementById(this.textbookTocService.textbookIds.contentId).scrollIntoView({ behavior: 'smooth' });
this.textbookTocService.resetTextbookIds();
});
}, 0);
}
this.telemetryGeneratorService.generateInteractTelemetry(
InteractType.OTHER,
InteractSubtype.IMPORT_COMPLETED,
Environment.HOME,
PageId.COLLECTION_DETAIL,
this.telemetryObject,
undefined,
this.objRollup,
this.corRelationList
);
this.telemetryGeneratorService.generateInteractTelemetry(
InteractType.OTHER,
InteractSubtype.IMPORT_COMPLETED,
Environment.HOME,
this.pageId,
this.telemetryObject,
undefined,
this.objRollup,
this.corRelationList
);
});
})
.catch(() => {
this.zone.run(() => {
this.showChildrenLoader = false;
});
});
}
private setTocData(content) {
this.childrenData = content.children;
this.collectionTocData = content;
}
getContentsSize(data) {
data.forEach((value) => {
this.breadCrumb.set(value.identifier, value.contentData.name);
if (value.contentData.size) {
this.downloadSize += Number(value.contentData.size);
}
if (!value.children) {
if (value.isAvailableLocally) {
this.localResourseCount++;
}
}
if (value.children) {
this.getContentsSize(value.children);
}
if (!value.isAvailableLocally && value.contentData.downloadUrl) {
this.downloadIdentifiers.add(value.contentData.identifier);
this.rollUpMap[value.contentData.identifier] = ContentUtil.generateRollUp(value.hierarchyInfo, undefined);
}
});
if (this.downloadIdentifiers.size && !this.isDownloadCompleted) {
this.showDownloadBtn = true;
}
}
navigateToDetailsPage(content: any, depth, corRelationData?) {
const corRelationList = [...this.corRelationList];
if (corRelationData) {
corRelationList.push(corRelationData);
}
this.zone.run(() => {
switch (ContentUtil.isTrackable(content)) {
case 1:
case 0:
this.navService.navigateToTrackableCollection({
content,
depth,
contentState: this.stateData,
corRelation: corRelationList
});
break;
case -1:
this.navService.navigateToContent({
isChildContent: true,
content,
depth,
contentState: this.stateData,
corRelation: corRelationList,
breadCrumb: this.breadCrumb
});
}
});
}
/**
* Reset all values
*/
resetVariables() {
this.isDownloadStarted = false;
this.showLoading = false;
this.refreshHeader();
this.downloadProgress = 0;
this.cardData = '';
this.contentDetail = undefined;
this.showDownload = false;
this.showDownloadBtn = false;
this.downloadIdentifiers = new Set();
this.queuedIdentifiers = [];
this.isDownloadCompleted = false;
this.currentCount = 0;
this.downloadPercentage = 0;
this.isUpdateAvailable = false;
}
/**
* Subscribe Sunbird-SDK event to get content download progress
*/
subscribeSdkEvent() {
this.eventSubscription = this.eventBusService.events().subscribe((event: EventsBusEvent) => {
this.zone.run(() => {
if (event.type === DownloadEventType.PROGRESS) {
const downloadEvent = event as DownloadProgress;
if (downloadEvent.payload.identifier === this.contentDetail.identifier) {
this.downloadProgress = downloadEvent.payload.progress === -1 ? 0 : downloadEvent.payload.progress;
if (this.downloadProgress === 100) {
this.showLoading = false;
this.refreshHeader();
this.contentDetail.isAvailableLocally = true;
}
}
}
if (event.payload && event.type === ContentEventType.SERVER_CONTENT_DATA) {
this.licenseDetails = event.payload.licenseDetails;
}
// Get child content
if (event.type === ContentEventType.CONTENT_EXTRACT_COMPLETED) {
const contentImportedEvent = event as ContentImportCompleted;
if (this.queuedIdentifiers.length && this.isDownloadStarted) {
if (this.queuedIdentifiers.includes(contentImportedEvent.payload.contentId)) {
this.currentCount++;
this.downloadPercentage = +((this.currentCount / this.queuedIdentifiers.length) * (100)).toFixed(0);
}
if (this.queuedIdentifiers.length === this.currentCount) {
this.showLoading = false;
this.refreshHeader();
this.isDownloadStarted = false;
this.showDownloadBtn = false;
this.isDownloadCompleted = true;
this.showDownload = false;
if (this.contentDetail) {
this.contentDetail.isAvailableLocally = true;
}
this.downloadPercentage = 0;
this.updateSavedResources();
this.setChildContents();
}
} else if (this.parentContent && contentImportedEvent.payload.contentId === this.contentDetail.identifier) {
// this condition is for when the child content update is available and we have downloaded parent content
// but we have to refresh only the child content.
this.showLoading = false;
this.refreshHeader();
this.setContentDetails(this.identifier, false);
} else {
if (this.isUpdateAvailable && contentImportedEvent.payload.contentId === this.contentDetail.identifier) {
this.showLoading = false;
this.refreshHeader();
this.setContentDetails(this.identifier, false);
} else {
if (contentImportedEvent.payload.contentId === this.contentDetail.identifier) {
this.showLoading = false;
this.refreshHeader();
this.updateSavedResources();
this.setChildContents();
this.contentDetail.isAvailableLocally = true;
}
}
}
}
if (event.type === ContentEventType.IMPORT_PROGRESS) {
const totalCountMsg = Math.floor((event.payload.currentCount / event.payload.totalCount) * 100) +
'% (' + event.payload.currentCount + ' / ' + event.payload.totalCount + ')';
this.importProgressMessage = this.commonUtilService.translateMessage('EXTRACTING_CONTENT', totalCountMsg);
if (event.payload.currentCount === event.payload.totalCount) {
let timer = 30;
const interval = setInterval(() => {
this.importProgressMessage = `Getting things ready in ${timer--} seconds`;
if (timer === 0) {
this.importProgressMessage = 'Getting things ready';
clearInterval(interval);
}
}, 1000);
}
}
// For content update available
const hierarchyInfo = this.cardData.hierarchyInfo ? this.cardData.hierarchyInfo : null;
const contentUpdateEvent = event as ContentUpdate;
if (contentUpdateEvent.type === ContentEventType.UPDATE && hierarchyInfo === null) {
this.zone.run(() => {
if (this.parentContent) {
const parentIdentifier = this.parentContent.contentId || this.parentContent.identifier;
this.showLoading = true;
this.telemetryGeneratorService.generateSpineLoadingTelemetry(this.contentDetail, false);
this.importContent([parentIdentifier], false);
} else {
this.setContentDetails(this.identifier, false);
}
});
}
});
}) as any;
}
updateSavedResources() {
this.events.publish('savedResources:update', {
update: true
});
}
async share() {
const popover = await this.popoverCtrl.create({
component: SbSharePopupComponent,
componentProps: {
content: this.contentDetail,
corRelationList: this.corRelationList,
objRollup: this.objRollup,
pageId: this.pageId,
shareItemType: ShareItemType.ROOT_COLECTION
},
cssClass: 'sb-popover',
});
await popover.present();
}
/**
* Download single content
*/
downloadAllContent(): void {
this.downloadProgress = 0;
this.showLoading = true;
this.isDownloadStarted = true;
this.downloadPercentage = 0;
this.showDownload = true;
this.showCollapsedPopup = false;
this.importContent(Array.from(this.downloadIdentifiers), true, true);
}
generateImpressionEvent(objectId, objectType, objectVersion) {
this.telemetryGeneratorService.generateImpressionTelemetry(
ImpressionType.DETAIL, '',
PageId.COLLECTION_DETAIL,
Environment.HOME,
objectId,
objectType,
objectVersion,
this.objRollup,
this.corRelationList);
this.telemetryGeneratorService.generateImpressionTelemetry(
ImpressionType.DETAIL, '',
this.pageId,
Environment.HOME,
objectId,
objectType,
objectVersion,
this.objRollup,
this.corRelationList);
}
generateStartEvent(objectId, objectType, objectVersion) {
const telemetryObject = new TelemetryObject(objectId, objectType, objectVersion);
this.telemetryGeneratorService.generateStartTelemetry(
PageId.COLLECTION_DETAIL,
telemetryObject,
this.objRollup,
this.corRelationList);
this.telemetryGeneratorService.generateStartTelemetry(
this.pageId,
telemetryObject,
this.objRollup,
this.corRelationList);
}
generateEndEvent(objectId, objectType, objectVersion) {
const telemetryObject = new TelemetryObject(objectId, objectType, objectVersion);
this.telemetryGeneratorService.generateEndTelemetry(
objectType ? objectType : CsPrimaryCategory.DIGITAL_TEXTBOOK,
Mode.PLAY,
PageId.COLLECTION_DETAIL,
Environment.HOME,
telemetryObject,
this.objRollup,
this.corRelationList);
this.telemetryGeneratorService.generateEndTelemetry(
objectType ? objectType : CsPrimaryCategory.DIGITAL_TEXTBOOK,
Mode.PLAY,
this.pageId,
Environment.HOME,
telemetryObject,
this.objRollup,
this.corRelationList);
}
generateQRSessionEndEvent(pageId: string, qrData: string) {
if (pageId !== undefined) {
const telemetryObject = new TelemetryObject(qrData, 'qr', '');
this.telemetryGeneratorService.generateEndTelemetry(
'qr',
Mode.PLAY,
pageId,
Environment.HOME,
telemetryObject,
undefined,
this.corRelationList);
}
}
async showDownloadConfirmationAlert() {
this.telemetryGeneratorService.generateInteractTelemetry(InteractType.TOUCH,
InteractSubtype.DOWNLOAD_CLICKED,
Environment.HOME,
PageId.COLLECTION_DETAIL,
this.telemetryObject,
undefined,
this.objRollup,
this.corRelationList);
this.telemetryGeneratorService.generateInteractTelemetry(InteractType.TOUCH,
InteractSubtype.DOWNLOAD_CLICKED,
Environment.HOME,
this.pageId,
this.telemetryObject,
undefined,
this.objRollup,
this.corRelationList);
if (this.commonUtilService.networkInfo.isNetworkAvailable) {
const contentTypeCount = this.downloadIdentifiers.size ? this.downloadIdentifiers.size : '';
const popover = await this.popoverCtrl.create({
component: ConfirmAlertComponent,
componentProps: {
sbPopoverHeading: this.commonUtilService.translateMessage('DOWNLOAD'),
sbPopoverMainTitle: this.contentDetail.contentData.name,
actionsButtons: [
{
btntext: this.commonUtilService.translateMessage('DOWNLOAD'),
btnClass: 'popover-color'
},
],
icon: null,
metaInfo: this.commonUtilService.translateMessage('ITEMS', contentTypeCount)
+ ' (' + this.fileSizePipe.transform(this.downloadSize, 2) + ')',
},
cssClass: 'sb-popover info',
});
await popover.present();
this.telemetryGeneratorService.generateImpressionTelemetry(ImpressionType.VIEW, '',
PageId.DOWNLOAD_ALL_CONFIRMATION_POPUP,
Environment.HOME,
this.contentDetail.identifier,
this.contentDetail.contentData.contentType,
this.contentDetail.contentData.pkgVersion,
this.objRollup,
this.corRelationList);
const response = await popover.onDidDismiss();
if (response && response.data) {
this.telemetryGeneratorService.generateInteractTelemetry(InteractType.TOUCH,
InteractSubtype.DOWNLOAD_ALL_CLICKED,
Environment.HOME,
PageId.COLLECTION_DETAIL,
this.telemetryObject,
undefined,
this.objRollup,
this.corRelationList);
this.telemetryGeneratorService.generateInteractTelemetry(InteractType.TOUCH,
InteractSubtype.DOWNLOAD_ALL_CLICKED,
Environment.HOME,
this.pageId,
this.telemetryObject,
undefined,
this.objRollup,
this.corRelationList);
this.downloadAllContent();
this.events.publish('header:decreasezIndex');
} else {
this.generateCancelDownloadTelemetry();
}
} else {
this.commonUtilService.showToast('ERROR_NO_INTERNET_MESSAGE');
}
}
mergeProperties(mergeProp) {
return ContentUtil.mergeProperties(this.contentDetail.contentData, mergeProp);
}
cancelDownload() {
this.telemetryGeneratorService.generateCancelDownloadTelemetry(this.contentDetail);
this.contentService.cancelDownload(this.identifier).toPromise().finally(() => {
this.zone.run(() => {
this.showLoading = false;
this.refreshHeader();
this.location.back();
});
});
}
generateCancelDownloadTelemetry() {
const values = new Map();
this.telemetryGeneratorService.generateInteractTelemetry(
InteractType.TOUCH,
InteractSubtype.CLOSE_CLICKED,
Environment.HOME,
PageId.COLLECTION_DETAIL,
this.telemetryObject,
values, this.objRollup,
this.corRelationList);
this.telemetryGeneratorService.generateInteractTelemetry(
InteractType.TOUCH,
InteractSubtype.CLOSE_CLICKED,
Environment.HOME,
this.pageId,
this.telemetryObject,
values, this.objRollup,
this.corRelationList);
}
/**
* Ionic life cycle hook
*/
ionViewWillLeave() {
this.downloadProgress = 0;
this.headerObservable.unsubscribe();
this.events.unsubscribe(EventTopics.CONTENT_TO_PLAY);
this.events.publish('header:setzIndexToNormal');
if (this.eventSubscription) {
this.eventSubscription.unsubscribe();
}
if (this.backButtonFunc) {
this.backButtonFunc.unsubscribe();
}
this.events.unsubscribe(EventTopics.DEEPLINK_COLLECTION_PAGE_OPEN);
}
async showDeletePopOver() {
this.contentDeleteObservable = this.contentDeleteHandler.contentDeleteCompleted$.subscribe(() => {
this.location.back();
});
const contentInfo: ContentInfo = {
telemetryObject: this.telemetryObject,
rollUp: this.objRollup,
correlationList: this.corRelationList,
hierachyInfo: undefined,
};
this.contentDeleteHandler.showContentDeletePopup(this.contentDetail, this.isChild, contentInfo, this.pageId);
}
refreshHeader() {
this.headerConfig = this.headerService.getDefaultPageConfig();
this.headerConfig.actionButtons = ['download'];
this.headerConfig.showBurgerMenu = false;
this.headerConfig.showHeader = true;
this.headerService.updatePageConfig(this.headerConfig);
this.events.publish('header:setzIndexToNormal');
}
handleHeaderEvents($event) {
switch ($event.name) {
case 'back':
this.telemetryGeneratorService.generateBackClickedTelemetry(PageId.COLLECTION_DETAIL, Environment.HOME,
true, this.cardData.identifier, this.corRelationList);
this.telemetryGeneratorService.generateBackClickedTelemetry(this.pageId, Environment.HOME,
true, this.cardData.identifier, this.corRelationList);
this.handleBackButton();
break;
case 'download':
this.redirectToActivedownloads();
break;
}
}
private redirectToActivedownloads() {
this.telemetryGeneratorService.generateInteractTelemetry(
InteractType.TOUCH,
InteractSubtype.ACTIVE_DOWNLOADS_CLICKED,
Environment.HOME,
PageId.COLLECTION_DETAIL,
this.telemetryObject,
undefined, this.objRollup,
this.corRelationList);
this.telemetryGeneratorService.generateInteractTelemetry(
InteractType.TOUCH,
InteractSubtype.ACTIVE_DOWNLOADS_CLICKED,
Environment.HOME,
this.pageId,
this.telemetryObject,
undefined, this.objRollup,
this.corRelationList);
this.router.navigate([RouterLinks.ACTIVE_DOWNLOADS]);
}
async onFilterMimeTypeChange(val, idx, currentFilter?) {
this.activeMimeTypeFilter = val;
this.currentFilter = this.commonUtilService.translateMessage(currentFilter);
this.mimeTypes.forEach((type) => {
type.selected = false;
});
this.mimeTypes[idx].selected = true;
this.telemetryGeneratorService.generateInteractTelemetry(
InteractType.TOUCH,
InteractSubtype.FILTER_CLICKED,
Environment.HOME,
PageId.COLLECTION_DETAIL,
this.telemetryObject,
undefined,
this.objRollup,
this.corRelationList);
this.telemetryGeneratorService.generateInteractTelemetry(
InteractType.TOUCH,
InteractSubtype.FILTER_CLICKED,
Environment.HOME,
this.pageId,
this.telemetryObject,
undefined,
this.objRollup,
this.corRelationList);
}
openTextbookToc() {
this.hiddenGroups.clear();
this.shownGroups = undefined;
this.navService.navigateTo([`/${RouterLinks.COLLECTION_DETAIL_ETB}/${RouterLinks.TEXTBOOK_TOC}`],
{ childrenData: this.childrenData, parentId: this.identifier });
this.telemetryGeneratorService.generateInteractTelemetry(
InteractType.TOUCH,
InteractSubtype.DROPDOWN_CLICKED,
Environment.HOME,
PageId.COLLECTION_DETAIL,
this.telemetryObject,
undefined,
this.objRollup,
this.corRelationList
);
this.telemetryGeneratorService.generateInteractTelemetry(
InteractType.TOUCH,
InteractSubtype.DROPDOWN_CLICKED,
Environment.HOME,
this.pageId,
this.telemetryObject,
undefined,
this.objRollup,
this.corRelationList
);
}
onScroll(event) {
if (event.detail.scrollTop >= 205) {
(this.stickyPillsRef.nativeElement as HTMLDivElement).classList.add('sticky');
const boxes: HTMLElement[] = Array.from(document.getElementsByClassName('sticky-header-title-box')) as HTMLElement[];
let headerBottomOffset = (this.stickyPillsRef.nativeElement as HTMLDivElement).getBoundingClientRect().bottom;
if (this.previousHeaderBottomOffset && this.previousHeaderBottomOffset > headerBottomOffset) {
headerBottomOffset = this.previousHeaderBottomOffset;
}
this.previousHeaderBottomOffset = headerBottomOffset;
const boxesData = boxes.map(b => {
return {
elem: b,
text: b.dataset['text'],
renderLevel: parseInt(b.dataset['renderLevel'], 10),
offsetTop: b.getBoundingClientRect().top
};
});
const activeBoxes = boxesData.filter(data => {
return data.offsetTop < headerBottomOffset
&& (data.offsetTop + data.elem.getBoundingClientRect().height) > headerBottomOffset;
});
if (!activeBoxes.length) {
return;
}
const activeBox = activeBoxes.reduce((acc, box) => {
if (acc.renderLevel > box.renderLevel) {
return acc;
} else {
return box;
}
}, activeBoxes[0]);
if (activeBox.text) {
this.stckyUnitTitle = activeBox.text;
}
return;
}
(this.stickyPillsRef.nativeElement as HTMLDivElement).classList.remove('sticky');
}
importContentInBackground(identifiers: Array<string>, isChild: boolean) {
if (this.showLoading && !this.isDownloadStarted) {
this.headerService.hideHeader();
}
const option: ContentImportRequest = {
contentImportArray: this.getImportContentRequestBody(identifiers, isChild),
contentStatusArray: ['Live'],
fields: ['appIcon', 'name', 'subject', 'size', 'gradeLevel'],
};
// Call content service
this.contentService.importContent(option).toPromise()
.then((data: ContentImportResponse[]) => {
this.zone.run(() => {
if (data && data.length && this.isDownloadStarted) {
data.forEach((value) => {
if (value.status === ContentImportStatus.ENQUEUED_FOR_DOWNLOAD) {
this.queuedIdentifiers.push(value.identifier);
} else if (value.status === ContentImportStatus.NOT_FOUND) {
this.faultyIdentifiers.push(value.identifier);
}
});
if (this.faultyIdentifiers.length > 0) {
const stackTrace: any = {};
stackTrace.parentIdentifier = this.cardData.identifier;
stackTrace.faultyIdentifiers = this.faultyIdentifiers;
this.telemetryGeneratorService.generateErrorTelemetry(Environment.HOME,
TelemetryErrorCode.ERR_DOWNLOAD_FAILED,
ErrorType.SYSTEM,
PageId.COLLECTION_DETAIL,
JSON.stringify(stackTrace),
);
this.telemetryGeneratorService.generateErrorTelemetry(Environment.HOME,
TelemetryErrorCode.ERR_DOWNLOAD_FAILED,
ErrorType.SYSTEM,
this.pageId,
JSON.stringify(stackTrace),
);
}
} else if (data && data[0].status === ContentImportStatus.NOT_FOUND) {
this.showLoading = false;
this.showChildrenLoader = false;
this.childrenData.length = 0;
}
});
})
.catch((error: any) => {
this.zone.run(() => {
this.showDownloadBtn = true;
this.isDownloadStarted = false;
this.showLoading = false;
if (error && (error.error === 'NETWORK_ERROR' || error.error === 'CONNECTION_ERROR')) {
this.commonUtilService.showToast('NEED_INTERNET_TO_CHANGE');
} else {
this.commonUtilService.showToast('UNABLE_TO_FETCH_CONTENT');
}
this.showChildrenLoader = false;
this.location.back();
});
});
}
playContent(event, corRelationData?) {
const corRelationList = [...this.corRelationList];
if (corRelationData) {
corRelationList.push(corRelationData);
}
const telemetryDetails = {
pageId: this.pageId,
corRelationList
};
const navExtras = {
state: {
isChildContent: true,
content: event.content,
depth: 1,
contentState: this.stateData,
corRelation: corRelationList,
breadCrumb: this.breadCrumb
}
};
this.contentPlayerHandler.playContent(event.content, navExtras, telemetryDetails, false);
}
tocCardClick(event) {
if (!(event.event instanceof Event)) {
return;
}
const corRelationData = {
id: (event && event.rollup[0]) || '',
type: CorReleationDataType.ROOT_ID
};
this.setActiveContentData(event, InteractSubtype.CONTENT_CLICKED, corRelationData);
this.navigateToDetailsPage(event.data, 1, corRelationData);
}
playButtonClick(event) {
const corRelationData = {
id: (event && event.rollup[0]) || '',
type: CorReleationDataType.ROOT_ID
};
this.setActiveContentData(event, InteractSubtype.PLAY_CLICKED, corRelationData);
this.playContent({ content: event.data }, corRelationData);
}
private setActiveContentData(event, telemetrySubType, corRelationData) {
this.activeContent = event.data;
this.textbookTocService.setTextbookIds({ contentId: event.data.identifier, rootUnitId: undefined });
const corRelationList = [...this.corRelationList];
if (corRelationData) {
corRelationList.push(corRelationData);
}
const values = {
contentClicked: event.data && event.data.identifier
};
const telemetryObj = ContentUtil.getTelemetryObject(event.data);
this.telemetryGeneratorService.generateInteractTelemetry(
InteractType.TOUCH,
telemetrySubType,
Environment.HOME,
PageId.TEXTBOOK_TOC, telemetryObj,
values,
this.objRollup, corRelationList
);
}
contentInfo() {
this.showContentDetails = !this.showContentDetails;
}
}
<ion-content class="ion-no-padding" [scrollEvents]="true" (ionScroll)="onScroll($event)">
<div class="content-padding">
<app-detail-card
(downloadAllContent)="showDownloadConfirmationAlert()"
(shareEvent)="share()"
(showOverflowMenuEvent)="showDeletePopOver()"
[contentDetail]="contentDetail"
[localImage]="contentDetail?.contentData?.appIcon"
[showDownloadBtn]="showDownloadBtn"
[isDepthChild]='isDepthChild'
[defaultAppIcon]="defaultAppIcon"
[trackDownloads]="trackDownloads$">
</app-detail-card>
<!-- End of the Parent Card -->
<!-- End import content -->
<div class="m-n" *ngIf="showSheenAnimation">
<div class="skeleton-search-card" *ngFor="let i of [0,1,2,3,4,5,6,7,8,9,10,11,12,13]">
<div style=" flex: 22 auto;">
<app-skeleton-item height="60px" width="100%" style="height:3.75rem; width:100%; margin-bottom: 10px;">
</app-skeleton-item>
</div>
</div>
</div>
<div #stickyPillsRef *ngIf="!showSheenAnimation && childrenData && childrenData?.length"
class="collection-etb-filter">
<div class="sb-chapter-dd pl-16" role="button" (click)="openTextbookToc()">
<span class="pull-left">{{stckyUnitTitle || ('SELECT_CHAPTER' | translate)}}</span>
<!-- set aria hidden true because in device the icon is not showing and talkback is speak that text -->
<span class="pull-right" aria-hidden="true">
<ion-icon md="caret-forward-circle" ios="chevron-forward-circle"></ion-icon>
</span>
</div>
<div class="sb-slider-pills-container">
<div class="sb-pills-container sb-grade-pills-container" id="gradeScroll">
<div role="button" class="pill" *ngFor="let type of mimeTypes; let i = index; let first = first"
[ngClass]="{'active': type?.selected, '': !type?.selected}" attr.id="class{{i}}" [attr.aria-selected]="type?.selected"
(click)="onFilterMimeTypeChange(type.value, i, type.name);">
<span class="img-align" *ngIf="type?.iconNormal && type?.selected">
<img aria-hidden="true" class="filter-icon" src="{{type?.iconActive}}" alt="video">
</span>
<span class="img-align" *ngIf="type?.iconNormal && !type?.selected">
<img aria-hidden="true" class="filter-icon" src="{{type?.iconNormal}}" alt="interactive">
</span>
<span class="allign-middle" attr.aria-label="{{type?.name | translate}}">{{type?.name | translate}}</span>
</div>
</div>
</div>
</div>
</div>
<div *ngIf="shouldPillsStick" style="height: 3rem;"></div>
<div>
<!-- Looping Inside Children Data Textbook -->
<section *ngIf="!showSheenAnimation && childrenData" class="textbook-accordian">
<sb-toc-item
[accordianConfig]="accordianConfig"
[type]="TocCardType.TRACKABLE"
[tocData]="collectionTocData"
[playBtnConfig]="playBtnConfig"
(tocCardClick)="tocCardClick($event)"
[activeMimeTypeFilter]="activeMimeTypeFilter"
[activeContent]="activeContent"
(playButtonClick)="playButtonClick($event)"
[trackableDefaultImage]="'assets/imgs/ic_courses_selected_joyful.svg'">
</sb-toc-item>
</section>
</div>
<div *ngIf="contentDetail?.contentData?.author || contentDetail?.contentData?.organisation
||contentDetail?.contentData?.license || licenseDetails || contentDetail?.contentData?.copyright">
<div class="m-8">
<div class="collection-etb-details">
<div class="title" (click)="contentInfo()">
<strong class="pull-left">{{'DETAILS' | translate}}</strong>
<span class="pull-right">
<ion-icon md="caret-forward-circle" ios="chevron-forward-circle"></ion-icon>
</span>
</div>
<div *ngIf="content && showContentDetails">
<app-relevant-content-card
[contentData]="contentDetail?.contentData"
[isAlreadyEnrolled]="isAlreadyEnrolled">
</app-relevant-content-card>
</div>
</div>
<app-license-card-component
[content]="contentDetail?.contentData"
[licenseDetails]="licenseDetails"
[appName]="appName"
[objRollup]="objRollup"
[corRelationList]="corRelationList"
[pageId]="pageId">
</app-license-card-component>
</div>
</div>
</ion-content>
<div>
<add-activity-to-group [pageId]="pageId" [identifier]="identifier"></add-activity-to-group>
</div>
<ng-container *ngIf="trackDownloads$ | async; let downloads">
<app-sb-download-popup *ngIf="downloads.queued.length"
(cancelDownloadEmit)="cancelDownload($event)"
[currentCount]="downloads.completed.length"
[queuedIdentifiers]="(downloads.queued.length+downloads.completed.length)"
[downloadSize]="downloadSize"
[collectionName]="contentDetail?.contentData?.name"
[showDownload]="true"
[showPopover]="showCollapsedPopup">
</app-sb-download-popup>
</ng-container>
./collection-detail-etb.page.scss
@import "src/assets/styles/base/_variables.scss";
@import "src/assets/styles/_custom-mixins.scss";
@import "src/assets/styles/_variables.scss";
// :host {
.sb-slider-pills-container {
.sb-grade-pills-container {
.pill {
min-height: 2.188rem;
border-radius: 50px;
}
}
}
.heading {
margin-top: 50px;
font-size: $font-size-base;
font-weight: bold;
line-height: 1.188rem;
text-align: center;
color: map-get($colors, granite_gray);
}
.sub-heading {
color: map-get($colors, granite_gray);
font-size: 0.75rem;
line-height: 1.063rem;
text-align: center;
}
.filter-icon {
// margin-right: 8px;
height: 0.938rem;
width: 0.938rem;
}
.img-align {
margin-top: 5px;
display: inline-block;
vertical-align: middle;
width: 0.938rem;
margin-right: 8px;
}
.allign-middle {
display: inline-block;
vertical-align: middle;
}
.collection-etb-filter {
&.sticky {
position: sticky;
top: 0;
left: 0;
z-index: 10;
}
}
.loading-backdrop {
.backdrop-container {
width: 100%;
padding: 16px;
text-align: center;
position: absolute;
top: 50%;
margin-top: -50px;
}
.backdrop-footer {
position: absolute;
width: 100%;
bottom: 0;
padding-bottom: 16px;
}
background-color: map-get($colors, white);
height: 100%;
z-index: 1000;
opacity: 1 !important;
}
ion-card {
display: flex;
flex-direction: column;
width: 100% !important;
box-shadow: 0 3px 5px 4px rgba(0, 0, 0, 0.05);
margin: 1px;
}
ion-card .card .card-md {
margin: 0;
}
.M0 {
margin: 0 !important;
}
.P15 {
padding: 15px !important;
}
.M5 {
margin: 5px;
}
.P5 {
padding: 5px;
}
.MT20 {
margin-top: 20px;
}
.MT10 {
margin-top: 10px;
}
.MB16 {
margin-bottom: 16px;
}
.MR5 {
margin-right: 5px;
}
.ML5 {
margin-left: 5px;
}
.ML10 {
margin-left: 10px;
}
.MLR0 {
margin-left: 0 !important;
margin-right: 0 !important;
}
.ML20 {
margin-left: 20px;
}
.P10 {
padding: 10px;
}
.secondChildren {
margin-left: 15px;
}
.thirdChildren {
margin-left: 25px;
}
.margin-10 {
margin-left: 10px;
}
.f24 {
font-size: 1.5rem;
}
.yellow-gold {
color: map-get($colors, bright_yellow);
}
.font-blue {
color: $blue;
font-size: 1.875rem;
}
.text-selected {
padding: 4px;
color: $blue;
font-weight: bolder;
}
.text-unselected {
padding: 4px;
color: map-get($colors, bright_blue);
}
.play-icon {
color: map-get($colors, vivid_green);
font-size: 1.875rem;
}
.font-14 {
font-size: $font-size-base !important;
}
.view-credits {
span {
color: $blue;
ion-icon {
padding: 0 0 4px 8px;
vertical-align: middle;
font-size: 1.125rem;
float: right !important;
}
}
}
.credit-label-padding {
padding: 14px 14px 8px 14px;
background-color: map-get($colors, white_f2);
}
.content-padding {
padding: 8px 8px 0 8px;
}
.subtitle-color {
color: map-get($colors, granite_gray);
}
.label-margin-bottom {
margin-bottom: 3px !important;
}
.traning-derived-label-background {
background-color: map-get($colors, white_f2);
padding: 8px 0px 8px 15px;
}
.font-12 {
font-size: 0.75rem !important;
}
.showLicensce {
p {
margin-bottom: 16px;
}
}
.grey-icon-span {
position: relative;
top: 0.5rem;
vertical-align: super;
}
.checkmark-icon {
color: map-get($colors, vivid_green);
font-size: 1.125rem;
margin-left: 5px;
}
.font-blue-text {
padding: 4px;
color: $blue;
}
.font-grey-text {
// padding: 4px;
color: map-get($colors, dark_gray);
}
.grey-icon {
color: map-get($colors, dark_gray);
font-size: ($font-size-base + 0.25);
}
.horizontal-scroll {
display: flex;
overflow-x: auto;
}
.separator-dot {
width: 0.25rem;
height: 0.25rem;
background-color: map-get($colors, light_silver);
border-radius: 50%;
display: inline-block;
vertical-align: middle;
}
.separator-line {
height: 0.063rem;
opacity: 0.36;
background-color: map-get($colors, dark_gray);
width: 100%;
}
.white {
color: map-get($colors, white);
}
.light-black {
color: map-get($colors, light_black_51);
}
.bg-white {
background-color: map-get($colors, white);
}
.bg-sucess {
background-color: $green;
}
.bg-primary {
background-color: $blue;
}
.bg-danger {
background-color: $orange;
}
.bg-dark-danger {
background-color: $red;
}
.danger {
color: $orange;
}
// Details card
.details-card {
border-radius: 2px;
box-shadow: 0 3px 5px 4px rgba(0, 0, 0, 0.05);
background-color: map-get($colors, white);
.content-unit {
display: grid;
//grid-gap: 13px;
grid-template-columns: 3fr .4fr;
.pull-right {
overflow: hidden;
display: grid;
grid-template-columns: 1fr;
margin-right: 5px;
padding: 10px;
font-size: 2rem;
.item {
flex: 1 1 auto;
justify-content: right;
align-items: center;
display: flex;
}
}
.left {
overflow: hidden;
grid-template-columns: 1fr;
display: flex;
flex-direction: column;
@include padding(15px, 0, 15px, 15px);
.item {
flex: 1 1 auto;
justify-content: left;
align-items: center;
display: flex;
}
}
}
.W-88 {
width: 5.5rem;
}
.rating {
display: flex;
justify-content: flex-end;
align-items: end;
}
.content {
display: grid;
//grid-gap: 13px;
grid-template-columns: 2.9fr 1fr;
.pull-right {
overflow: hidden;
display: grid;
grid-template-columns: 1fr;
margin-right: 5px;
padding: 10px;
font-size: 2rem;
}
.right {
overflow: hidden;
display: grid;
grid-template-columns: 1fr;
padding: 15px;
//grid-template-rows: 1fr;
.img-container {
// background-color: grey;
width: 100%;
min-height: 3.375rem;
max-height: 3.375rem;
}
}
.left {
overflow: hidden;
grid-template-columns: 1fr;
display: flex;
flex-direction: column;
@include padding(15px, 0, 15px, 15px);
.item {
flex: 1 1 auto;
justify-content: left;
align-items: center;
display: flex;
}
.title {
width: 100%;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
margin: 0 0 3px;
padding: 0;
font-weight: 500;
font-style: normal;
font-stretch: normal;
line-height: normal;
letter-spacing: -0.4px;
color: map-get($colors, primary_black);
height: 2.625rem;
}
.info {
font-size: 0.75rem;
font-weight: 500;
font-style: normal;
font-stretch: normal;
line-height: normal;
letter-spacing: -0.4px;
color: map-get($colors, dark_gray);
}
}
&.single-column {
display: grid;
grid-template-columns: 1fr;
.left {
@include padding(15px);
}
.tag {
border-radius: 2px;
@include padding(3px, 7px);
color: map-get($colors, light-blue);
font-size: 0.625rem;
font-weight: normal;
font-style: normal;
font-stretch: normal;
line-height: 1.1;
letter-spacing: -0.4px;
border: 1px solid map-get($colors, light-blue);
display: inline-flex;
&:not(:last-child) {
@include margin(null, 10px, null, null);
}
}
}
}
.btn-caption-container {
display: inline-grid;
grid-template-columns: 1fr;
@include margin(null, 20px, null, null);
&:last-child {
@include margin(null, 0, null, null);
}
.btn-caption {
color: map-get($colors, secondary-light);
text-transform: capitalize;
font-weight: 500;
font-style: normal;
font-stretch: normal;
line-height: normal;
letter-spacing: -0.3px;
display: inline-block;
text-align: center;
}
.action-btn {
height: auto;
ion-icon {
line-height: 1.88rem;
}
}
}
}
.scroll-content {
padding-bottom: 20% !important;
}
.sb-row {
width: 100%;
}
.sb-topics-containe {
padding-right: 5%;
}
.sb-hidden-content {
background-color: map-get($colors, white_f2);
height: 34.15%;
width: 100%;
border-radius: 0 0 2px 2px;
padding-top: 2%;
padding-bottom: 5%;
}
.sb-accordian-card {
height: 6.1%;
width: 100%;
border-radius: 2px;
background-color: map-get($colors, white);
box-shadow: 0 4px 7px 0 rgba(0, 0, 0, 0.1);
}
.sb-topic-text {
&.sb-topic-text {
padding-top: 5px;
}
height: 2.44%;
width: 80%;
color: $blue;
font-size: $font-size-base;
line-height: 1.25rem;
}
.box-align {
// margin-right: 18px;
}
// }
.sb-chapter-dd {
@include clearfix;
color: $blue;
padding: $base-block-space;
background-color: map-get($colors, white);
.pull-left {
line-height: 1.88rem;
}
ion-icon {
height: 1.5rem;
width: 1.5rem;
border-radius: 12px;
font-size: 1.75rem;
color: map-get($colors, light-blue);
}
}
.sb-topics-container-toc {
.sb-topic-item {
color: $primary-color;
padding: 8px;
}
.sb-ftue-design {
.pull-right {
display: none;
}
.unit-hierachy {
color: $primary-color;
padding: 8px;
}
}
.sb-chapter-dd {
border-bottom: 1px solid $gray-100;
}
.sb-collection-child-ftue {
margin-left: 8px;
}
}
.drop-arrow{
border-radius: 50%;
background-color: map-get($colors, white);
height: 1.5rem;
width: 1.5rem;
padding-top: 8px;
img{
height: 0.5rem;
}
}
.collection-etb-details{
border-radius: 1rem;
background-color: var(--app-white);
margin-bottom: 1rem;
padding: 0 0 1rem;
box-shadow: var(--button-style-shadow) !important;
.title{
color: var(--app-primary);
padding: 1rem;
}
}