+
{{'CERTIFICATE' | translate}}
diff --git a/src/app/manage-learn/project/project-details/project-details.component.ts b/src/app/manage-learn/project/project-details/project-details.component.ts
index e85594ac35..c11c4df03f 100644
--- a/src/app/manage-learn/project/project-details/project-details.component.ts
+++ b/src/app/manage-learn/project/project-details/project-details.component.ts
@@ -43,7 +43,7 @@ export class ProjectDetailsComponent implements OnInit {
taskCount = 0;
projectDetailsCopy;
taskNoDataFound="FRMELEMNTS_LBL_PLEASE_CREATE_AND_COMPLETE_TASKS"
-
+ certificateCriteria:any =[];
constructor(
public params: ActivatedRoute,
private headerService: AppHeaderService,
@@ -126,6 +126,16 @@ export class ProjectDetailsComponent implements OnInit {
if (success.docs.length) {
this.categories = [];
this.projectDetails = success.docs.length ? success.docs[0] : {};
+ if(this.projectDetails.certificate){
+ this.certificateCriteria =[];
+ let criteria = Object.keys(this.projectDetails?.certificate?.criteria?.conditions);
+ criteria.forEach(element => {
+ let config ={
+ name:this.projectDetails?.certificate?.criteria?.conditions[element].validationText
+ }
+ this.certificateCriteria.push(config);
+ })
+ }
this.setActionButtons();
this.isNotSynced = this.projectDetails ? (this.projectDetails.isNew || this.projectDetails.isEdit) : false;
this.projectDetails.categories.forEach((category: any) => {
@@ -188,7 +198,11 @@ export class ProjectDetailsComponent implements OnInit {
defaultOptions[0] = actions.NOT_DOWNLOADED;
}
if (this.projectDetails.status === statusType.submitted) {
- defaultOptions = actions.SUBMITTED_PROJECT_ACTIONS
+ if(this.projectDetails.certificate){
+ defaultOptions = actions.SUBMITTED_PROJECT_ACTIONS.concat(actions.CERTIFICATE_ACTION);
+ }else{
+ defaultOptions = actions.SUBMITTED_PROJECT_ACTIONS
+ }
}
this.projectActions = defaultOptions;
}
@@ -233,6 +247,9 @@ export class ProjectDetailsComponent implements OnInit {
case 'edit':
this.router.navigate([`/${RouterLinks.PROJECT}/${RouterLinks.PROJECT_EDIT}`, this.projectDetails._id]);
break;
+ case 'certificate':
+ this.getProjectsApi(true);
+ break
}
}
@@ -267,13 +284,14 @@ export class ProjectDetailsComponent implements OnInit {
})
}
- getProjectsApi() {
+ getProjectsApi(certificate?) {
const payload = {
projectId: this.projectId,
solutionId: this.solutionId,
isProfileInfoRequired: false,
programId: this.programId,
- templateId: this.templateId
+ templateId: this.templateId,
+ certificate : certificate
};
this.projectServ.getProjectDetails(payload);
}
diff --git a/src/app/manage-learn/project/project-listing/project-listing.component.html b/src/app/manage-learn/project/project-listing/project-listing.component.html
index 517c743201..88123d155e 100644
--- a/src/app/manage-learn/project/project-listing/project-listing.component.html
+++ b/src/app/manage-learn/project/project-listing/project-listing.component.html
@@ -20,7 +20,7 @@
-
+
{{'CERTIFICATE' | translate}}
diff --git a/src/app/manage-learn/project/project-listing/project-listing.component.ts b/src/app/manage-learn/project/project-listing/project-listing.component.ts
index 40c182c1b6..dc1b482dc4 100644
--- a/src/app/manage-learn/project/project-listing/project-listing.component.ts
+++ b/src/app/manage-learn/project/project-listing/project-listing.component.ts
@@ -284,7 +284,10 @@ export class ProjectListingComponent {
programId: project.programId,
solutionId: project.solutionId,
type: selectedFilter,
+ listing: 'project'
},
+ skipLocationChange: true,
+ replaceUrl: true,
});
} else {
this.router.navigate([`${RouterLinks.PROJECT}/${RouterLinks.DETAILS}`], {
diff --git a/src/app/manage-learn/project/project-templateview/project-templateview.page.html b/src/app/manage-learn/project/project-templateview/project-templateview.page.html
index 0c499ff0cc..702c94b96b 100644
--- a/src/app/manage-learn/project/project-templateview/project-templateview.page.html
+++ b/src/app/manage-learn/project/project-templateview/project-templateview.page.html
@@ -1,5 +1,14 @@
+
+
+
+
+
+
+
+ {{'CERTIFICATE' | translate}}
+
{{buttonLabel |
translate}}
@@ -22,7 +31,7 @@
-
diff --git a/src/app/manage-learn/project/project-templateview/project-templateview.page.ts b/src/app/manage-learn/project/project-templateview/project-templateview.page.ts
index d9f1be6ee5..a95a756264 100644
--- a/src/app/manage-learn/project/project-templateview/project-templateview.page.ts
+++ b/src/app/manage-learn/project/project-templateview/project-templateview.page.ts
@@ -1,6 +1,6 @@
-import { Component, OnInit } from '@angular/core';
+import { Component, OnInit, Inject } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
-import { AlertController, PopoverController } from '@ionic/angular';
+import { AlertController, Platform, PopoverController } from '@ionic/angular';
import * as _ from 'underscore';
import { TranslateService } from '@ngx-translate/core';
import { statuses } from '../../core/constants/statuses.constant';
@@ -11,7 +11,14 @@ import { RouterLinks } from '@app/app/app.constant';
import { actions } from '../../core/constants/actions.constants';
import { GenericPopUpService } from '../../shared';
import { AppGlobalService } from '@app/services';
+import { PreferenceKey } from '@app/app/app.constant';
+import { Subscription } from 'rxjs';
+import {
+ SharedPreferences
+} from 'sunbird-sdk';
+import { ProfileNameConfirmationPopoverComponent } from '@app/app/components/popups/sb-profile-name-confirmation-popup/sb-profile-name-confirmation-popup.component';
+import { Location } from '@angular/common';
@Component({
selector: 'app-project-templateview',
templateUrl: './project-templateview.page.html',
@@ -58,7 +65,18 @@ export class ProjectTemplateviewPage implements OnInit {
stateData;
isATargetedSolution;
isAssignedProject : boolean = false;
+ isStarted : boolean = false;
+ hideNameConfirmPopup = false;
+ certificateCriteria:any =[];
+ userId;
+ clickedOnProfile :boolean = false;
+ projectlisting:boolean = false;
+ programlisting:boolean = false;
+
+ public backButtonFunc: Subscription;
+
constructor(
+ @Inject('SHARED_PREFERENCES') private preferences: SharedPreferences,
public params: ActivatedRoute,
public popoverController: PopoverController,
private router: Router,
@@ -69,9 +87,10 @@ export class ProjectTemplateviewPage implements OnInit {
private popupService: GenericPopUpService,
private appGlobalService: AppGlobalService,
private alert: AlertController,
- private toast :ToastService
+ private toast :ToastService,
+ private platform : Platform,
+ private location :Location
) {
-
params.params.subscribe((parameters) => {
this.id = parameters.id;
});
@@ -81,6 +100,9 @@ export class ProjectTemplateviewPage implements OnInit {
this.solutionId = parameters.solutionId;
this.isATargetedSolution = (parameters.isATargetedSolution === 'true');
this.isAssignedProject = parameters.type == 'assignedToMe' ? true : false
+ this.programlisting = (parameters.listing == "program");
+ this.projectlisting = (parameters.listing == "project");
+
});
this.stateData = this.router.getCurrentNavigation().extras.state;
this.templateDetailsPayload = this.router.getCurrentNavigation().extras.state;
@@ -126,22 +148,36 @@ export class ProjectTemplateviewPage implements OnInit {
}
}
- ngOnInit() {
+ async ngOnInit() {
+ this.userId = await this.appGlobalService.getActiveProfileUid();
+ const key = PreferenceKey.DO_NOT_SHOW_PROFILE_NAME_CONFIRMATION_POPUP + '-' + this.userId;
+ this.hideNameConfirmPopup = await this.preferences.getBoolean(key).toPromise();
+ }
+ ionViewWillEnter() {
this.headerConfig = this.headerService.getDefaultPageConfig();
this.headerConfig.actionButtons = [];
- this.headerConfig.showHeader = true;
+ this.headerConfig.showHeader = false;
this.headerConfig.showBurgerMenu = false;
this.headerService.updatePageConfig(this.headerConfig);
- }
-
- ionViewWillEnter() {
+ this.clickedOnProfile ? this.showProfileNameConfirmationPopup():'';
this.templateDetailsInit();
}
-
+ handleBackButton() {
+ this.location.back();
+ }
async getProjectApi() {
this.actionItems = await actions.PROJECT_ACTIONS;
let resp = await this.projectService.getTemplateBySoluntionId(this.id);
this.project = resp.result;
+ if(this.project.criteria){
+ let criteria = Object.keys(this.project?.criteria?.conditions);
+ criteria.forEach(element => {
+ let config ={
+ name:this.project?.criteria?.conditions[element].validationText
+ }
+ this.certificateCriteria.push(config);
+ })
+ }
this.metaData = {
title: this.project?.title,
subTitle: this.project?.programInformation ? this.project?.programInformation?.programName : ''
@@ -154,6 +190,15 @@ export class ProjectTemplateviewPage implements OnInit {
let resp = await this.projectService.getTemplateByExternalId(this.id);
this.programId = resp?.result?.programInformation?.programId || null;
this.project = resp?.result;
+ if(this.project.certificate){
+ let criteria = Object.keys(this.project?.criteria?.conditions);
+ criteria.forEach(element => {
+ let config ={
+ name:this.project?.certificate?.conditions[element].validationText
+ }
+ this.certificateCriteria.push(config);
+ })
+ }
if (this.project?.projectId) {
this.buttonLabel = 'FRMELEMNTS_LBL_CONTINUE_IMPROVEMENT'
}
@@ -176,6 +221,9 @@ export class ProjectTemplateviewPage implements OnInit {
}
doAction() {
+ if(!this.hideNameConfirmPopup && this.project.criteria && !this.isStarted && this.project.hasAcceptedTAndC && (this.isAssignedProject || this.isTargeted || this.isATargetedSolution)){
+ this.showProfileNameConfirmationPopup();
+ }else{
if(this.templateDetailsPayload?.referenceFrom == "observation" && !this.project?.projectId){
this.startProjectConfirmation();
return;
@@ -184,17 +232,26 @@ export class ProjectTemplateviewPage implements OnInit {
this.triggerLogin();
return
}
- if ( !this.isAssignedProject && !this.project.hasAcceptedTAndC && !this.isTargeted && !this.isATargetedSolution) {
+ if ( !this.isAssignedProject && !this.project.hasAcceptedTAndC && !this.isTargeted && !this.isATargetedSolution && !this.isStarted) {
this.popupService.showPPPForProjectPopUp('FRMELEMNTS_LBL_PROJECT_PRIVACY_POLICY', 'FRMELEMNTS_LBL_PROJECT_PRIVACY_POLICY_TC', 'FRMELEMNTS_LBL_TCANDCP', 'FRMELEMNTS_LBL_SHARE_PROJECT_DETAILS', 'https://diksha.gov.in/term-of-use.html', 'privacyPolicy').then((data: any) => {
- if (data && data.isClicked) {
+ if (data && data.isClicked) {
this.project.hasAcceptedTAndC = data.isChecked;
+ if(this.project.criteria && !this.isStarted && !this.hideNameConfirmPopup){
+ this.showProfileNameConfirmationPopup();
+ }else{
this.start();
this.toast.showMessage('FRMELEMNTS_LBL_PROJECT_STARTED','success');
+ }
}
})
} else {
+ if(this.project.criteria && !this.isStarted && !this.hideNameConfirmPopup){
+ this.showProfileNameConfirmationPopup();
+ }else{
this.start();
}
+ }
+ }
}
gotoDetails() {
@@ -209,6 +266,20 @@ export class ProjectTemplateviewPage implements OnInit {
}
async start() {
+ await this.router.navigate([`/${RouterLinks.HOME}`]);
+ if(this.projectlisting){
+ await this.router
+ .navigate([`/${RouterLinks.PROJECT}`], {
+ queryParams: {
+ selectedFilter: this.isAssignedProject? 'assignedToMe' : 'discoveredByMe',
+ }
+ })
+ }
+ if(this.programlisting){
+ await this.router.navigate([`/${RouterLinks.PROGRAM}`]);
+ await this.router.navigate([`/${RouterLinks.PROGRAM}/${RouterLinks.SOLUTIONS}`, this.programId]);
+ }
+ setTimeout(() => {
if (this.stateData?.referenceFrom === 'link') {
this.startProjectsFromLink();
} else if (this.project.projectId) {
@@ -228,10 +299,12 @@ export class ProjectTemplateviewPage implements OnInit {
hasAcceptedTAndC: this.project.hasAcceptedTAndC,
detailsPayload: this.stateData ? this.stateData : null,
templateId: this.templateId,
- replaceUrl: true
+ replaceUrl: true,
+ certificate:false
}
this.projectService.getProjectDetails(payload);
}
+ },900)
}
startProjectsFromLink() {
@@ -249,7 +322,8 @@ export class ProjectTemplateviewPage implements OnInit {
isProfileInfoRequired: true,
hasAcceptedTAndC: this.project.hasAcceptedTAndC,
templateId: this.templateId,
- replaceUrl: false
+ replaceUrl: false,
+ certificate:false
}
this.projectService.getProjectDetails(payload);
})
@@ -302,4 +376,47 @@ export class ProjectTemplateviewPage implements OnInit {
}
})
}
+ private async showProfileNameConfirmationPopup() {
+ let listing;
+ if(this.projectlisting){
+ listing = 'project'
+ }else if(this.programlisting){
+ listing = 'program'
+ }else{
+ listing = false
+ }
+ let params ={
+ isTargeted :this.isTargeted,
+ programId: this.programId,
+ solutionId :this.solutionId,
+ isATargetedSolution :this.isATargetedSolution ,
+ type :this.isAssignedProject ? 'assignedToMe' : 'createdByMe',
+ listing : listing
+ }
+ this.router.navigate([`${RouterLinks.PROJECT}/${RouterLinks.PROJECT_TEMPLATE}`, this.solutionId], {
+ queryParams: params,
+ skipLocationChange: false,
+ replaceUrl: true,
+ state: {
+ "referenceFrom": "link",
+ }})
+
+ this.clickedOnProfile = true;
+ const popUp = await this.popoverController.create({
+ component: ProfileNameConfirmationPopoverComponent,
+ componentProps: {
+ projectContent: this.project
+ },
+ cssClass: 'sb-popover sb-profile-name-confirmation-popover',
+ });
+ await popUp.present();
+ const { data } = await popUp.onDidDismiss();
+ if (data !== undefined) {
+ if (data.buttonClicked) {
+ this.isStarted = true;
+ this.clickedOnProfile = false;
+ this.doAction();
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/src/app/manage-learn/shared/components/accordion-list/accordion-list.component.html b/src/app/manage-learn/shared/components/accordion-list/accordion-list.component.html
index da28408c38..3df74caf5b 100644
--- a/src/app/manage-learn/shared/components/accordion-list/accordion-list.component.html
+++ b/src/app/manage-learn/shared/components/accordion-list/accordion-list.component.html
@@ -17,7 +17,7 @@
-
> {{content?.text}}
+
> {{content?.name}}
diff --git a/src/app/manage-learn/shared/components/entity-search-local/entity-search-local.component.html b/src/app/manage-learn/shared/components/entity-search-local/entity-search-local.component.html
new file mode 100644
index 0000000000..e2ae466a17
--- /dev/null
+++ b/src/app/manage-learn/shared/components/entity-search-local/entity-search-local.component.html
@@ -0,0 +1,52 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
{{ 'EMPTY_SEARCH_RESULTS' | translate }}
+
+ {{'FRMELEMNTS_MSG_NO_DATA_FOR_LOCAL_SEARCH' | translate:{'entity': data.entityType} }}
+
+
+ {{ 'ADD' | translate }} {{data.entityType}}
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/app/manage-learn/shared/components/entity-search-local/entity-search-local.component.scss b/src/app/manage-learn/shared/components/entity-search-local/entity-search-local.component.scss
new file mode 100644
index 0000000000..286b883bf6
--- /dev/null
+++ b/src/app/manage-learn/shared/components/entity-search-local/entity-search-local.component.scss
@@ -0,0 +1,7 @@
+.m-10-15{
+ margin: 10px 15px;
+}
+.backbtn{
+ padding-left: 10px;
+ color: var(--primary);
+}
\ No newline at end of file
diff --git a/src/app/manage-learn/shared/components/entity-search-local/entity-search-local.component.ts b/src/app/manage-learn/shared/components/entity-search-local/entity-search-local.component.ts
new file mode 100644
index 0000000000..d061e25a77
--- /dev/null
+++ b/src/app/manage-learn/shared/components/entity-search-local/entity-search-local.component.ts
@@ -0,0 +1,36 @@
+import { Component, OnInit } from '@angular/core';
+import { ModalController, NavParams } from '@ionic/angular';
+@Component({
+ selector: 'app-entity-search-local',
+ templateUrl: './entity-search-local.component.html',
+ styleUrls: ['./entity-search-local.component.scss'],
+})
+export class EntitySearchLocalComponent implements OnInit {
+
+ data :any =[];
+ searchText : string;
+ searchQuery : string;
+
+ constructor(
+ private navParams: NavParams,
+ private modalCtrl: ModalController,
+ ) {
+ this.data = this.navParams.get('data');
+ }
+
+ ngOnInit() {}
+
+ entityClickAction(entity,action){
+ this.modalCtrl.dismiss({action:action, entity:entity});
+ }
+ onSearch(){
+ this.searchText = this.searchQuery;
+ }
+ addEntity(){
+ this.modalCtrl.dismiss({action:'addEntity'});
+ }
+ close(){
+ this.modalCtrl.dismiss();
+ }
+
+}
diff --git a/src/app/manage-learn/shared/components/entityfilter/entityfilter.component.ts b/src/app/manage-learn/shared/components/entityfilter/entityfilter.component.ts
index 7b48b18ef7..26d1d30db1 100644
--- a/src/app/manage-learn/shared/components/entityfilter/entityfilter.component.ts
+++ b/src/app/manage-learn/shared/components/entityfilter/entityfilter.component.ts
@@ -38,6 +38,7 @@ export class EntityfilterComponent implements OnInit {
payload;
entityType;
selectedItems: any = [];
+ entity:any;
constructor(
private localStorage: LocalStorageService,
private navParams: NavParams,
@@ -52,6 +53,7 @@ export class EntityfilterComponent implements OnInit {
this.searchUrl = urlConstants.API_URLS.SEARCH_ENTITY;
this.observationId = this.navParams.get('data');
this.solutionId = this.navParams.get('solutionId');
+ this.entity = this.navParams.get('entity');
// this.localStorage
// .getLocalStorage('profileRole')
}
diff --git a/src/app/manage-learn/shared/components/index.ts b/src/app/manage-learn/shared/components/index.ts
index 0c7c50cd9c..81e34234c9 100644
--- a/src/app/manage-learn/shared/components/index.ts
+++ b/src/app/manage-learn/shared/components/index.ts
@@ -30,4 +30,5 @@ export * from './add-link-modal/add-link-modal.component';
export * from './attachment-card/attachment-card.component';
export * from './attachment-lists/attachment-lists.component';
export * from './report-list/report-list.component';
+export * from './entity-search-local/entity-search-local.component';
export * from './start-improvement/start-improvement.component';
diff --git a/src/app/manage-learn/shared/components/item-list-card/item-list-card.component.html b/src/app/manage-learn/shared/components/item-list-card/item-list-card.component.html
index b9c4d2ca00..1cc18ddc4a 100644
--- a/src/app/manage-learn/shared/components/item-list-card/item-list-card.component.html
+++ b/src/app/manage-learn/shared/components/item-list-card/item-list-card.component.html
@@ -7,7 +7,9 @@
- {{ title | titlecase }}
+ {{ title | titlecase }}
+ , {{code}}
+
diff --git a/src/app/manage-learn/shared/components/item-list-card/item-list-card.component.scss b/src/app/manage-learn/shared/components/item-list-card/item-list-card.component.scss
index 9496e3d8e8..95ea2fcf1c 100644
--- a/src/app/manage-learn/shared/components/item-list-card/item-list-card.component.scss
+++ b/src/app/manage-learn/shared/components/item-list-card/item-list-card.component.scss
@@ -27,6 +27,9 @@ ion-card-header {
padding-top: 8px;
padding-bottom: 8px;
background: #ffffff;
+ ion-card-content{
+ word-break: break-all;
+ }
}
.alterCard{
diff --git a/src/app/manage-learn/shared/components/item-list-card/item-list-card.component.ts b/src/app/manage-learn/shared/components/item-list-card/item-list-card.component.ts
index 7b071253c7..f33151ee6d 100644
--- a/src/app/manage-learn/shared/components/item-list-card/item-list-card.component.ts
+++ b/src/app/manage-learn/shared/components/item-list-card/item-list-card.component.ts
@@ -8,6 +8,7 @@ import { CommonUtilService } from '@app/services';
})
export class ItemListCardComponent implements OnChanges {
@Input() title: any;
+ @Input() code: any;
@Input() subTitle: any;
@Input() description:any;
@Input() case:any ={subTitle:'titleCase', description:'titleCase'}
diff --git a/src/app/manage-learn/shared/pipe/entity-local-search.ts b/src/app/manage-learn/shared/pipe/entity-local-search.ts
new file mode 100644
index 0000000000..9e8a7c6ef0
--- /dev/null
+++ b/src/app/manage-learn/shared/pipe/entity-local-search.ts
@@ -0,0 +1,15 @@
+import { Pipe, PipeTransform } from '@angular/core';
+
+@Pipe({
+ name: 'entitySearch',
+})
+export class EntitySearchPipe implements PipeTransform {
+ transform(value: any, args?: any): any {
+ if (!value) return null;
+ if (!args) return value;
+ args = args.toLowerCase();
+ return value.filter(function (item) {
+ return JSON.stringify(item).toLowerCase().includes(args);
+ });
+ }
+}
\ No newline at end of file
diff --git a/src/app/manage-learn/shared/shared.module.ts b/src/app/manage-learn/shared/shared.module.ts
index 49950d2eb7..c1364935d1 100644
--- a/src/app/manage-learn/shared/shared.module.ts
+++ b/src/app/manage-learn/shared/shared.module.ts
@@ -35,6 +35,7 @@ import {
AttachmentCardComponent,
AttachmentListsComponent,
ReportListComponent,
+ EntitySearchLocalComponent,
StartImprovementComponent
} from './components';
@@ -73,7 +74,7 @@ import { ExpansionPanelComponent } from './components/expansion-panel/expansion-
import { ExpansionTableComponent } from './components/expansion-table/expansion-table.component';
import { GenericPopUpService } from './generic.popup';
import { HTTP } from '@ionic-native/http/ngx';
-
+import { EntitySearchPipe } from './pipe/entity-local-search';
@NgModule({
declarations: [
CreateTaskComponent,
@@ -128,6 +129,8 @@ import { HTTP } from '@ionic-native/http/ngx';
AttachmentCardComponent,
AttachmentListsComponent,
ReportListComponent,
+ EntitySearchPipe,
+ EntitySearchLocalComponent,
StartImprovementComponent
],
@@ -185,6 +188,8 @@ import { HTTP } from '@ionic-native/http/ngx';
AddLinkModalComponent,
AttachmentCardComponent,
AttachmentListsComponent,
+ EntitySearchPipe,
+ EntitySearchLocalComponent,
StartImprovementComponent
],
providers: [
@@ -223,6 +228,7 @@ import { HTTP } from '@ionic-native/http/ngx';
ProjectTaskListComponent,
AddLinkModalComponent,
ReportListComponent,
+ EntitySearchLocalComponent,
StartImprovementComponent
],
diff --git a/src/app/my-groups/add-activity-to-group/add-activity-to-group.page.scss b/src/app/my-groups/add-activity-to-group/add-activity-to-group.page.scss
index 25e42d0d17..f38cb2a87c 100644
--- a/src/app/my-groups/add-activity-to-group/add-activity-to-group.page.scss
+++ b/src/app/my-groups/add-activity-to-group/add-activity-to-group.page.scss
@@ -3,6 +3,7 @@
margin: 0;
font-weight: bold;
padding: 16px;
+ color: var(--app-black)
}
.add-activity-container{
display: flex;
diff --git a/src/app/player/player.page.html b/src/app/player/player.page.html
index 2edb79fac1..7367aa4a74 100644
--- a/src/app/player/player.page.html
+++ b/src/app/player/player.page.html
@@ -16,6 +16,11 @@
(telemetryEvent)="playerTelemetryEvents($event)">
+
+
+

+
+
diff --git a/src/app/player/player.page.spec.ts b/src/app/player/player.page.spec.ts
index 81c43fa555..366438e895 100644
--- a/src/app/player/player.page.spec.ts
+++ b/src/app/player/player.page.spec.ts
@@ -3,7 +3,7 @@ import { StatusBar } from '@ionic-native/status-bar/ngx';
import { Platform, AlertController, PopoverController } from '@ionic/angular';
import { Events } from '@app/util/events';
import { CourseService, ProfileService, SunbirdSdk, TelemetryService , ContentService, TelemetryErrorCode,
- ErrorType, InteractType, SharedPreferences, PlayerService } from '@project-sunbird/sunbird-sdk';
+ ErrorType, InteractType, SharedPreferences, PlayerService } from 'sunbird-sdk';
import { AppGlobalService } from '../../services/app-global-service.service';
import { DownloadPdfService } from '../../services/download-pdf/download-pdf.service';
import { PlayerPage } from './player.page';
@@ -19,15 +19,22 @@ import { finalize } from 'rxjs/operators';
import { EventTopics, ExploreConstants, RouterLinks, ShareItemType } from '../app.constant';
import { PrintPdfService } from '@app/services/print-pdf/print-pdf.service';
import { ScreenOrientation } from '@ionic-native/screen-orientation/ngx';
-import { IterableDiffers } from '@angular/core';
import { Environment, InteractSubtype } from '../../services';
-
+import { File } from '@ionic-native/file/ngx';
+import { User, HierarchyInfo } from './player-action-handler-delegate';
+import { UpdateContentStateRequest, UpdateContentStateTarget } from '@project-sunbird/sunbird-sdk';
+import { ElementRef } from '@angular/core';
declare const cordova;
describe('PlayerPage', () => {
let playerPage: PlayerPage;
+ window.cordova.plugins = {
+ InAppUpdateManager: {
+ checkForImmediateUpdate: jest.fn((fn, fn1) => {fn({}), fn1()})
+ }
+ };
const mockAlertCtrl: Partial
= {
};
@@ -37,7 +44,12 @@ describe('PlayerPage', () => {
const mockCanvasPlayerService: Partial = {
handleAction: jest.fn()
};
- const mockPlatform: Partial = {};
+ const mockPlatform: Partial = {
+ is: jest.fn(platform => platform === 'ios'),
+ pause: {
+ subscribe: jest.fn((fn) => fn({}))
+ } as any,
+ };
const mockScreenOrientation: Partial = {
unlock: jest.fn(),
ORIENTATIONS: {
@@ -48,8 +60,12 @@ describe('PlayerPage', () => {
};
const mockAppGlobalService: Partial = {
};
- const mockStatusBar: Partial = {};
- const mockEvents: Partial = {};
+ const mockStatusBar: Partial = {
+ hide: jest.fn()
+ };
+ const mockEvents: Partial = {
+ publish: jest.fn()
+ };
const mockCommonUtilService: Partial = {
translateMessage: jest.fn(),
handleAssessmentStatus: jest.fn(),
@@ -80,7 +96,8 @@ describe('PlayerPage', () => {
childContent: true
}
}
- })) as any
+ })) as any,
+ navigate: jest.fn()
};
const mockLocation: Partial = {
back: jest.fn()
@@ -92,7 +109,7 @@ describe('PlayerPage', () => {
// getPdfPlayerConfiguration: jest.fn(() => Promise.resolve({}))
};
const mockDownloadPdfService: Partial = {
- // downloadPdf: jest.fn(() => Promise.resolve({}))
+ downloadPdf: jest.fn(() => Promise.resolve({}))
};
const mockFileOpener: Partial = {};
const mockTransfer: Partial = {};
@@ -103,6 +120,15 @@ describe('PlayerPage', () => {
const mockprofileService: Partial = {};
const mockPlayerService: Partial = {};
const mockSharedPreferences: Partial = {};
+ const mockFile: Partial = {
+ checkDir: jest.fn(),
+ checkFile: jest.fn(),
+ createDir: jest.fn()
+ };
+ const mockTelemetryService: Partial = {};
+ const mockSunbirdSdk: Partial = {};
+ SunbirdSdk['_instance'] = mockSunbirdSdk as SunbirdSdk;
+
beforeAll(() => {
playerPage = new PlayerPage(
mockCourseService as CourseService,
@@ -127,7 +153,8 @@ describe('PlayerPage', () => {
mockFileOpener as FileOpener,
mockTransfer as FileTransfer,
mockTelemetryGeneratorService as TelemetryGeneratorService,
- mockprintPdfService as PrintPdfService
+ mockprintPdfService as PrintPdfService,
+ mockFile as File
);
});
@@ -141,13 +168,13 @@ describe('PlayerPage', () => {
});
describe('showConfirm' , () => {
-
it('should be called when player type is not sunbird old player', (done) =>{
playerPage.playerType = 'sunbird-pdf-player';
- mockAlertCtrl.create = jest.fn(() => Promise.resolve({
+ mockAlertCtrl.create = jest.fn((fn) => Promise.resolve({
present: jest.fn()
})) as any;
mockTelemetryGeneratorService.generateBackClickedNewTelemetry = jest.fn();
+ playerPage.handleNavBackButton();
playerPage.showConfirm();
setTimeout(() =>{
expect(mockTelemetryGeneratorService.generateBackClickedNewTelemetry).toHaveBeenCalled();
@@ -164,6 +191,7 @@ describe('PlayerPage', () => {
mockAlertCtrl.create = jest.fn(() => Promise.resolve({
present: jest.fn()
})) as any;
+ mockTelemetryGeneratorService.generateInteractTelemetry = jest.fn()
playerPage.previewElement= {
nativeElement: {
contentWindow: {
@@ -188,16 +216,82 @@ describe('PlayerPage', () => {
done()
}, 0)
})
- })
- describe('ionviewWillEnter', () => {
- it('should initialize the backbutton', (done) => {
+ it('should be called when player type is sunbird old player and exit app, if renderer is false', (done) =>{
playerPage.playerType = 'sunbird-old-player';
- playerPage.previewElement = {
+ mockAlertCtrl.create = jest.fn(() => Promise.resolve({
+ present: jest.fn()
+ })) as any;
+ mockTelemetryGeneratorService.generateInteractTelemetry = jest.fn()
+ playerPage.previewElement= {
nativeElement: {
- src: '12346'
+ contentWindow: {
+ EkstepRendererAPI : {
+ getCurrentStageId: jest.fn()
+ },
+ TelemetryService:{
+ interact: jest.fn()
+ },
+ Renderer : {
+ running: false
+ }
+ }
}
}
+ playerPage.showConfirm();
+ setTimeout(() =>{
+ expect(mockCommonUtilService.translateMessage).toHaveBeenNthCalledWith(1, 'CONFIRM');
+ expect(mockCommonUtilService.translateMessage).toHaveBeenNthCalledWith(2, 'CONTENT_PLAYER_EXIT_PERMISSION');
+ expect(mockCommonUtilService.translateMessage).toHaveBeenNthCalledWith(3, 'CANCEL');
+ expect(mockCommonUtilService.translateMessage).toHaveBeenNthCalledWith(4, 'OKAY');
+ done()
+ }, 0)
+ })
+ })
+
+ describe('ionviewWillEnter', () => {
+ it('should initialize the backbutton handle else case', async (done) => {
+ window.setInterval = jest.fn((fn) => fn({}), 500) as any;
+ playerPage.playerType ='sunbird-old-player';
+ playerPage.previewElement = {
+ nativeElement: ''
+ }
+ playerPage.config = {
+ context: {
+ actor: {
+ id: '123456'
+ }
+ },
+ metadata: {
+ basePath: 'basePath',
+ isAvailableLocally: false,
+ contentData:{
+ streamingUrl: ''
+ }
+ }
+ };
+ mockStatusBar.hide = jest.fn()
+ mockPlatform.backButton = {
+ subscribeWithPriority: jest.fn((_, fn) => fn()),
+ } as any;
+ mockAlertCtrl.getTop = jest.fn(() => Promise.resolve(undefined));
+ jest.spyOn(playerPage, 'showConfirm').mockImplementation(() => {
+ return Promise.resolve();
+ });
+ mockEvents.subscribe = jest.fn((_, fn) => fn({ showConfirmBox: true }));
+ playerPage.ionViewWillEnter();
+ setTimeout(() => {
+ // expect(playerPage.loadPdfPlayer).toBeTruthy();
+ expect(mockPlatform.backButton).toBeTruthy();
+ expect(mockAlertCtrl.getTop).toHaveBeenCalled();
+ // expect(mockLocation.back).toHaveBeenCalledWith();
+ expect(mockEvents.subscribe).toHaveBeenCalled();
+ done();
+ }, 0);
+ });
+ it('should initialize the backbutton', async (done) => {
+ window.setInterval = jest.fn((fn) => fn({}), 500) as any;
+ playerPage.playerType ='sunbird-old-player';
playerPage.config = {
context: {
actor: {
@@ -205,11 +299,28 @@ describe('PlayerPage', () => {
}
},
metadata: {
- basePath: 'basePath'
+ basePath: 'basePath',
+ isAvailableLocally: true,
+ contentData:{
+ streamingUrl: ''
}
- }
- // playerPage.loadPdfPlayer = true;
- mockStatusBar.hide = jest.fn();
+ }
+ };
+ const config = playerPage.config;
+ playerPage.previewElement = {
+ nativeElement: {
+ src: '12346',
+ onload: () => {},
+ contentWindow: {
+ cordova: '',
+ Media: '',
+ initializePreview: config,
+ addEventListener: jest.fn(fn => fn())
+ }
+ }
+ } as ElementRef;
+ window.setTimeout = jest.fn((fn) => fn({}), 1000) as any;
+ mockStatusBar.hide = jest.fn()
mockPlatform.backButton = {
subscribeWithPriority: jest.fn((_, fn) => fn()),
} as any;
@@ -217,7 +328,6 @@ describe('PlayerPage', () => {
jest.spyOn(playerPage, 'showConfirm').mockImplementation(() => {
return Promise.resolve();
});
- // mockLocation.back = jest.fn();
mockEvents.subscribe = jest.fn((_, fn) => fn({ showConfirmBox: true }));
playerPage.ionViewWillEnter();
setTimeout(() => {
@@ -230,86 +340,90 @@ describe('PlayerPage', () => {
}, 0);
});
- });
-
- it('should initialize back button when mimetype is questionset', (done) => {
- playerPage.previewElement = {
- nativeElement: {
- src: '12346'
+ it('should initialize back button when mimetype is questionset', () => {
+ window.setInterval = jest.fn((fn) => fn({}), 500) as any;
+ playerPage.previewElement = {
+ nativeElement: {
+ src: '12346'
+ }
}
- }
- playerPage.config = {
- context: {
- actor: {
- id: '123456'
+ playerPage.config = {
+ context: {
+ actor: {
+ id: '123456'
+ }
+ },
+ metadata: {
+ isAvailableLocally: true,
+ basePath: 'basePath',
+ mimeType: 'application/vnd.sunbird.questionset'
}
- },
- metadata: {
- basePath: 'basePath',
- mimeType: 'application/vnd.sunbird.questionset'
}
- }
- playerPage.playerType = 'sunbird-quml-player'
- mockStatusBar.hide = jest.fn();
- mockPlatform.backButton = {
- subscribeWithPriority: jest.fn((_, fn) => fn()),
- } as any;
- mockAlertCtrl.getTop = jest.fn(() => Promise.resolve(undefined));
- jest.spyOn(playerPage, 'showConfirm').mockImplementation(() => {
- return Promise.resolve();
+ playerPage.playerType = 'sunbird-quml-player'
+ mockStatusBar.hide = jest.fn();
+ mockPlatform.backButton = {
+ subscribeWithPriority: jest.fn((_, fn) => fn()),
+ } as any;
+ mockAlertCtrl.getTop = jest.fn(() => Promise.resolve(undefined));
+ jest.spyOn(playerPage, 'showConfirm').mockImplementation(() => {
+ return Promise.resolve();
+ });
+ // mockLocation.back = jest.fn();
+ mockEvents.subscribe = jest.fn((_, fn) => fn({ showConfirmBox: true }));
+ playerPage.ionViewWillEnter();
+ setTimeout(() => {
+ // expect(playerPage.loadPdfPlayer).toBeTruthy();
+ expect(mockPlatform.backButton).toBeTruthy();
+ expect(mockAlertCtrl.getTop).toHaveBeenCalled();
+ expect(mockEvents.subscribe).toHaveBeenCalled();
+ expect(playerPage.showConfirm).toHaveBeenCalled();
+ }, 0);
});
- // mockLocation.back = jest.fn();
- mockEvents.subscribe = jest.fn((_, fn) => fn({ showConfirmBox: true }));
- playerPage.ionViewWillEnter();
- setTimeout(() => {
- // expect(playerPage.loadPdfPlayer).toBeTruthy();
- expect(mockPlatform.backButton).toBeTruthy();
- expect(mockAlertCtrl.getTop).toHaveBeenCalled();
- expect(mockEvents.subscribe).toHaveBeenCalled();
- expect(playerPage.showConfirm).toHaveBeenCalled();
- done();
- }, 0);
- });
- it('should initialize back button when mimetype is not questionset', (done) => {
- playerPage.previewElement = {
- nativeElement: {
- src: '12346'
- }
- };
- playerPage.config = {
- context: {
- actor: {
- id: '123456'
+ it('should initialize back button when mimetype is not questionset', () => {
+ window.setInterval = jest.fn((fn) => fn({}), 500) as any;
+ playerPage.previewElement = {
+ nativeElement: {
+ src: '12346',
+ contentWindow: {
+ EkstepRendererAPI: {
+ getCurrentStageId: jest.fn()
+ },
+ TelemetryService: {
+ exit: jest.fn()
+ }
+ }
}
- },
- metadata: {
- basePath: 'basePath',
- mimeType: 'application'
- }
- };
- playerPage.playerType = 'sunbird-pdf-player';
- // playerPage.loadPdfPlayer = true;
- mockStatusBar.hide = jest.fn();
- mockPlatform.backButton = {
- subscribeWithPriority: jest.fn((_, fn) => fn()),
- } as any;
- mockAlertCtrl.getTop = jest.fn(() => Promise.resolve(undefined));
- jest.spyOn(playerPage, 'showConfirm').mockImplementation(() => {
- return Promise.resolve();
+ };
+ playerPage.config = {
+ context: {
+ actor: {
+ id: '123456'
+ }
+ },
+ metadata: {
+ basePath: 'basePath',
+ mimeType: 'application'
+ }
+ };
+ playerPage.playerType = 'sunbird-pdf-player';
+ // playerPage.loadPdfPlayer = true;
+ mockStatusBar.hide = jest.fn();
+ mockPlatform.backButton = {
+ subscribeWithPriority: jest.fn((_, fn) => fn()),
+ } as any;
+ mockAlertCtrl.getTop = jest.fn(() => Promise.resolve({}));
+ mockEvents.subscribe = jest.fn((_, fn) => fn({ showConfirmBox: false }));
+ mockEvents.publish = jest.fn()
+ mockAppGlobalService.getSelectedUser = jest.fn();
+ playerPage.ionViewWillEnter();
+ setTimeout(() => {
+ expect(mockPlatform.backButton).toBeTruthy();
+ }, 0);
});
- mockEvents.subscribe = jest.fn((_, fn) => fn({ showConfirmBox: true }));
- playerPage.ionViewWillEnter();
- setTimeout(() => {
- expect(mockPlatform.backButton).toBeTruthy();
- expect(mockAlertCtrl.getTop).toHaveBeenCalled();
- expect(mockEvents.subscribe).toHaveBeenCalled();
- done();
- }, 0);
});
-
- it('should return new player config', (done) => {
+ it('should return new player config', () => {
playerPage.config = {
context: {
objectRollup: {
@@ -345,12 +459,11 @@ describe('PlayerPage', () => {
playerPage.getNewPlayerConfiguration();
setTimeout(() => {
expect(mockprofileService.getActiveSessionProfile).toBeCalled();
- done();
}, 0)
// expect(playerPage.getNewPlayerConfiguration()).toHaveBeenCalled();
})
- it('should call the get question read api for instructions', (done) =>{
+ it('should call the get question read api for instructions', () =>{
playerPage.config = {
context: {
objectRollup: {
@@ -365,7 +478,7 @@ describe('PlayerPage', () => {
},
metadata: {
identifier: 'identifier',
- isAvailableLocally: true,
+ isAvailableLocally: false,
basePath: 'basePath',
instructions: 'int',
contentData: {
@@ -396,7 +509,47 @@ describe('PlayerPage', () => {
playerPage.getNewPlayerConfiguration();
setTimeout(() =>{
expect(mockContentService.getQuestionSetRead).toHaveBeenCalled();
- done()
+ } , 0)
+ });
+
+ it('should handle error the get question read api for instructions', () =>{
+ playerPage.config = {
+ context: {
+ objectRollup: {
+ l1: 'li'
+ },
+ dispatcher: {
+ dispatch: jest.fn()
+ },
+ pdata: {
+ pid: 'sunbird.app.contentplayer'
+ }
+ },
+ metadata: {
+ identifier: 'identifier',
+ isAvailableLocally: false,
+ basePath: 'basePath',
+ instructions: 'int',
+ contentData: {
+ mimeType: 'application/vnd.sunbird.questionset',
+ isAvailableLocally: true,
+ basePath: 'basePath',
+ streamingUrl: 'streamingurl'
+ }
+ }
+ }
+
+ mockprofileService.getActiveSessionProfile = jest.fn(() => of({
+ serverProfile:{
+ firstName: 'firstName',
+ lastName: 'lastname'
+ }
+ })) as any;
+
+ mockContentService.getQuestionSetRead = jest.fn(() => throwError({})) as any;
+ playerPage.getNewPlayerConfiguration();
+ setTimeout(() =>{
+ expect(mockContentService.getQuestionSetRead).toHaveBeenCalled();
} , 0)
});
@@ -425,7 +578,8 @@ describe('PlayerPage', () => {
}
playerPage.checkIsPlayerEnabled(config, 'pdfPlayer');
})
- it('should return a content', (done)=> {
+
+ it('should return a content', ()=> {
mockContentService.nextContent = jest.fn(()=> of({
identifier: 'identifier',
@@ -440,7 +594,6 @@ describe('PlayerPage', () => {
playerPage.getNextContent({} , '1234')
setTimeout(() =>{
expect(mockContentService.nextContent).toHaveBeenCalled();
- done();
}, 0)
})
@@ -455,7 +608,7 @@ describe('PlayerPage', () => {
streamingUrl: 'streamingurl'
}
}
- mockEvents.publish = jest.fn(()=> []);
+ mockEvents.publish = jest.fn(()=> Promise.resolve());
mockLocation.back = jest.fn();
playerPage.playNextContent();
expect(mockEvents.publish).toHaveBeenCalledWith(EventTopics.NEXT_CONTENT , {
@@ -463,7 +616,8 @@ describe('PlayerPage', () => {
course : {}
});
expect(mockLocation.back).toHaveBeenCalled();
- })
+ });
+
describe('ionViewWillEnter', () => {
beforeEach(() => {
jest.useFakeTimers();
@@ -494,13 +648,15 @@ describe('PlayerPage', () => {
ContentUtil.generateRollUp(playerPage.config['metadata']['hierarchyInfo'], playerPage.config['metadata']['identifier']))
}, 100);
});
-});
+ });
+
describe('ngOninit', () => {
it('should call getPdfPlayerConfiguration', (done) => {
- const subscribeFn = jest.fn(() => { }) as any;
+ const subscribeFn = jest.fn(fn => fn()) as any;
mockPlatform.pause = {
- subscribe: subscribeFn
+ subscribe: jest.fn(fn => fn())
} as any;
+ document.getElementsByTagName = jest.fn(() => [{contentWindow: {postMessage: jest.fn()}}]) as any;
mockFormAndFrameworkUtilService.getPdfPlayerConfiguration = jest.fn(() => Promise.resolve({}));
playerPage.config = {
context: {
@@ -522,10 +678,13 @@ describe('PlayerPage', () => {
isAvailableLocally: true,
basePath: 'basePath',
streamingUrl: 'streamingurl'
+ },
+ hierarchyInfo: {
+ contentType: '',
+ identifier: 'string',
+ primaryCategory: ''
}
-
}
-
};
jest.spyOn(playerPage, 'checkIsPlayerEnabled').mockImplementation(() => {
return {
@@ -566,6 +725,7 @@ describe('PlayerPage', () => {
playerPage.config['context'].dispatcher.dispatch();
});
setTimeout(() => {
+ expect(mockPlatform.pause?.subscribe).toHaveBeenCalled();
// expect(mockFormAndFrameworkUtilService.getPdfPlayerConfiguration).toHaveBeenCalled();
expect(playerPage.loadPdfPlayer).toBeFalsy();
done();
@@ -574,10 +734,11 @@ describe('PlayerPage', () => {
it('should check mimetype and load pdf player', (done) => {
mockFormAndFrameworkUtilService.getPdfPlayerConfiguration = jest.fn(() => Promise.resolve({}));
playerPage.playerConfig = true;
- const subscribeFn = jest.fn(() => { }) as any;
+ const subscribeFn = jest.fn(fn => fn()) as any;
mockPlatform.pause = {
subscribe: subscribeFn
} as any;
+ document.getElementsByTagName = jest.fn(() => [{contentWindow: {postMessage: jest.fn()}}]) as any;
playerPage.config = {
context: {
dispatcher: {
@@ -590,9 +751,10 @@ describe('PlayerPage', () => {
l1: 'li'
}
},
+ config: {sideMenu: {sideMenu: true}},
metadata: {
identifier: 'li',
- mimeType: 'application/pdf',
+ mimeType: 'application/epub',
isAvailableLocally: true,
contentData: {
isAvailableLocally: true,
@@ -603,7 +765,7 @@ describe('PlayerPage', () => {
};
jest.spyOn(playerPage, 'checkIsPlayerEnabled').mockImplementation(() => {
return {
- name: 'pdfPlayer'
+ name: 'epubPlayer'
}
})
jest.spyOn(playerPage, 'getNewPlayerConfiguration').mockImplementation(() => {
@@ -633,14 +795,14 @@ describe('PlayerPage', () => {
});
});
-
it('should check mimetype and load video player', (done) => {
mockFormAndFrameworkUtilService.getPdfPlayerConfiguration = jest.fn(() => Promise.resolve({}));
playerPage.playerConfig = true;
- const subscribeFn = jest.fn(() => { }) as any;
+ const subscribeFn = jest.fn(fn => fn()) as any;
mockPlatform.pause = {
subscribe: subscribeFn
} as any;
+ document.getElementsByTagName = jest.fn(() => [{contentWindow: {postMessage: jest.fn()}}]) as any;
playerPage.config = {
context: {
dispatcher: {
@@ -706,13 +868,15 @@ describe('PlayerPage', () => {
});
});
- it('should check mimetype and load quml player', (done) => {
+ it('should check mimetype and load video player for platfrom ios', (done) => {
mockFormAndFrameworkUtilService.getPdfPlayerConfiguration = jest.fn(() => Promise.resolve({}));
playerPage.playerConfig = true;
- const subscribeFn = jest.fn(() => { }) as any;
+ const subscribeFn = jest.fn(fn => fn()) as any;
mockPlatform.pause = {
subscribe: subscribeFn
} as any;
+ document.getElementsByTagName = jest.fn(() => [{contentWindow: {postMessage: jest.fn()}}]) as any;
+ mockPlatform.is = jest.fn(platform => platform === "ios");
playerPage.config = {
context: {
dispatcher: {
@@ -737,7 +901,7 @@ describe('PlayerPage', () => {
},
metadata: {
identifier: 'li',
- mimeType: 'application/vnd.sunbird.questionset',
+ mimeType: 'video/mp4',
isAvailableLocally: true,
contentData: {
isAvailableLocally: true,
@@ -748,20 +912,19 @@ describe('PlayerPage', () => {
};
jest.spyOn(playerPage , 'checkIsPlayerEnabled').mockImplementation(() => {
return {
- name: 'qumlPlayer'
+ name: 'videoPlayer'
}
})
+ jest.spyOn(playerPage , 'getNewPlayerConfiguration').mockImplementation(() => {
+ return Promise.resolve(playerPage.config);
+ });
jest.spyOn(playerPage , 'getNextContent').mockImplementation(() => {
return Promise.resolve({contentId: 'sample content id',
identifier: 'sampleid', name: 'sample name'});
})
- jest.spyOn(playerPage , 'getNewPlayerConfiguration').mockImplementation(() => {
- return Promise.resolve(playerPage.config);
- });
playerPage.playerConfig = {};
- mockContentService.getQuestionSetChildren = jest.fn();
playerPage.ngOnInit().then(() => {
jest.spyOn(SunbirdSdk, 'instance', 'get').mockReturnValue({
telemetryService: {
@@ -778,40 +941,165 @@ describe('PlayerPage', () => {
playerPage.config['context'].dispatcher.dispatch({});
});
});
- });
-
- describe('toggleDeviceOrientation' , () => {
- it('should lock and unlock' , () => {
- //arrange
- mockScreenOrientation.type = 'landscape';
- mockScreenOrientation.unlock = jest.fn();
- mockScreenOrientation.lock = jest.fn(() => Promise.resolve('PORTRAIT'));
- //act
- playerPage.toggleDeviceOrientation();
- //assert
- expect(mockScreenOrientation.unlock).toHaveBeenCalled();
- expect(mockScreenOrientation.lock).toHaveBeenCalledWith('PORTRAIT');
- });
- it('should lock and unlock' , () =>{
- //arrange
- mockScreenOrientation.type = 'LANDSCAPE';
- mockScreenOrientation.unlock = jest.fn();
- mockScreenOrientation.lock = jest.fn(() => Promise.resolve('LANDSCAPE'));
- //act
- playerPage.toggleDeviceOrientation();
- //assert
- expect(mockScreenOrientation.unlock).toHaveBeenCalled();
- expect(mockScreenOrientation.lock).toHaveBeenCalledWith('LANDSCAPE');
- });
- });
- describe('pdfPlayerEvents', () => {
- it('should sync assessment events', () => {
- mockAppGlobalService.getCurrentUser = jest.fn(() => ({ uid: 'sample-uid' }));
- mockPlayerService.savePlayerState = jest.fn();
- mockCourseService.syncAssessmentEvents = jest.fn(() => of(undefined)) as any;
- const event = {
- edata: {
+ it('should check mimetype and load quml player', (done) => {
+ mockFormAndFrameworkUtilService.getPdfPlayerConfiguration = jest.fn(() => Promise.resolve({}));
+ playerPage.playerConfig = true;
+ const subscribeFn = jest.fn(fn => fn()) as any;
+ mockPlatform.pause = {
+ subscribe: subscribeFn
+ } as any;
+ document.getElementsByTagName = jest.fn(() => [{contentWindow: {postMessage: jest.fn()}}]) as any;
+ playerPage.config = {
+ context: {
+ dispatcher: {
+ // dispatch: jest.fn()
+ },
+ pdata: {
+ pid: 'sunbird.app.contentplayer'
+ },
+ objectRollup: {
+ l1: 'li'
+ }
+ },
+ config: {
+ sideMenu: {
+ showDownload: false,
+ showPrint: false,
+ showReplay: false,
+ showExit: true,
+ showShare: true,
+ showDeviceOrientation: true
+ }
+ },
+ metadata: {
+ identifier: 'li',
+ mimeType: 'application/vnd.sunbird.questionset',
+ isAvailableLocally: true,
+ contentData: {
+ isAvailableLocally: true,
+ basePath: 'basePath',
+ streamingUrl: 'streamingurl'
+ }
+ }
+ };
+ jest.spyOn(playerPage , 'checkIsPlayerEnabled').mockImplementation(() => {
+ return {
+ name: 'qumlPlayer'
+ }
+ })
+ jest.spyOn(playerPage , 'getNextContent').mockImplementation(() => {
+
+ return Promise.resolve({contentId: 'sample content id',
+ identifier: 'sampleid', name: 'sample name'});
+
+ })
+ jest.spyOn(playerPage , 'getNewPlayerConfiguration').mockImplementation(() => {
+ return Promise.resolve(playerPage.config);
+ });
+ playerPage.playerConfig = {};
+ mockContentService.getQuestionSetChildren = jest.fn();
+ playerPage.ngOnInit().then(() => {
+ jest.spyOn(SunbirdSdk, 'instance', 'get').mockReturnValue({
+ telemetryService: {
+ saveTelemetry: jest.fn((request: string) => {
+ return of(true).pipe(
+ finalize(() => {
+ done();
+
+ })
+ );
+ })
+ } as Partial as TelemetryService
+ } as Partial as SunbirdSdk);
+ playerPage.config['context'].dispatcher.dispatch({});
+ });
+ });
+
+ it('should check mimetype and load pdf player', (done) => {
+ mockFormAndFrameworkUtilService.getPdfPlayerConfiguration = jest.fn(() => Promise.resolve({}));
+ playerPage.playerConfig = true;
+ const subscribeFn = jest.fn(fn => fn()) as any;
+ mockPlatform.pause = {
+ subscribe: subscribeFn
+ } as any;
+ document.getElementsByTagName = jest.fn(() => []) as any;
+ playerPage.config = {
+ context: {
+ dispatcher: {
+ // dispatch: jest.fn()
+ },
+ pdata: {
+ pid: 'sunbird.app.contentplayer'
+ },
+ objectRollup: {
+ l1: 'li'
+ }
+ },
+ config: {sideMenu: {sideMenu: true}},
+ metadata: {
+ identifier: 'li',
+ mimeType: '',
+ isAvailableLocally: true,
+ contentData: {
+ isAvailableLocally: true,
+ basePath: 'basePath',
+ streamingUrl: 'streamingurl'
+ }
+ }
+ };
+ playerPage.playerConfig = {};
+ playerPage.ngOnInit().then(() => {
+ jest.spyOn(SunbirdSdk, 'instance', 'get').mockReturnValue({
+ telemetryService: {
+ saveTelemetry: jest.fn((request: string) => {
+ return of(true).pipe(
+ finalize(() => {
+ done();
+
+ })
+ );
+ })
+ } as Partial as TelemetryService
+ } as Partial as SunbirdSdk);
+ playerPage.config['context'].dispatcher.dispatch({});
+ });
+ });
+ });
+
+ describe('toggleDeviceOrientation' , () => {
+ it('should lock and unlock' , () => {
+ //arrange
+ mockScreenOrientation.type = 'landscape';
+ mockScreenOrientation.unlock = jest.fn();
+ mockScreenOrientation.lock = jest.fn(() => Promise.resolve('PORTRAIT'));
+ //act
+ playerPage.toggleDeviceOrientation();
+ //assert
+ expect(mockScreenOrientation.unlock).toHaveBeenCalled();
+ expect(mockScreenOrientation.lock).toHaveBeenCalledWith('PORTRAIT');
+ });
+
+ it('should lock and unlock' , () =>{
+ //arrange
+ mockScreenOrientation.type = 'LANDSCAPE';
+ mockScreenOrientation.unlock = jest.fn();
+ mockScreenOrientation.lock = jest.fn(() => Promise.resolve('LANDSCAPE'));
+ //act
+ playerPage.toggleDeviceOrientation();
+ //assert
+ expect(mockScreenOrientation.unlock).toHaveBeenCalled();
+ expect(mockScreenOrientation.lock).toHaveBeenCalledWith('LANDSCAPE');
+ });
+ });
+
+ describe('pdfPlayerEvents', () => {
+ it('should sync assessment events', () => {
+ mockAppGlobalService.getCurrentUser = jest.fn(() => ({ uid: 'sample-uid' }));
+ mockPlayerService.savePlayerState = jest.fn();
+ mockCourseService.syncAssessmentEvents = jest.fn(() => of(undefined)) as any;
+ const event = {
+ edata: {
type: 'END'
}
};
@@ -843,6 +1131,45 @@ describe('PlayerPage', () => {
expect(mockLocation.back).toHaveBeenCalled();
}, 50);
});
+ it('should exit the player and confirm if has metadata', () => {
+ mockAppGlobalService.getCurrentUser = jest.fn(() => ({ uid: 'sample-uid' }));
+ mockPlayerService.deletePlayerSaveState = jest.fn();
+ const event = {
+ edata: {
+ type: 'EXIT'
+ }
+ };
+ playerPage.isExitPopupShown = false;
+ playerPage.config = {
+ metadata: {
+ mimeType: 'application/vnd.sunbird.questionset'
+ }
+ }
+ playerPage.playerEvents(event);
+
+ setTimeout(() => {
+ }, 50);
+ });
+
+ it('should exit the player and confirm if has metadata on else case if isExit popup is shown', () => {
+ mockAppGlobalService.getCurrentUser = jest.fn(() => ({ uid: 'sample-uid' }));
+ mockPlayerService.deletePlayerSaveState = jest.fn();
+ const event = {
+ edata: {
+ type: 'EXIT'
+ }
+ };
+ playerPage.isExitPopupShown = true;
+ playerPage.config = {
+ metadata: {
+ mimeType: 'application/vnd.sunbird.questionset'
+ }
+ }
+ playerPage.playerEvents(event);
+
+ setTimeout(() => {
+ }, 50);
+ });
it('should call the download service to download the pdf', () => {
mockAppGlobalService.getCurrentUser = jest.fn(() => ({ uid: 'sample-uid' }));
playerPage['content'] = {
@@ -865,7 +1192,7 @@ describe('PlayerPage', () => {
}, 100);
});
- it('should call the download service to download the pdf for catch part', () => {
+ it('should call the print service to print the pdf for catch part', () => {
mockAppGlobalService.getCurrentUser = jest.fn(() => ({ uid: 'sample-uid' }));
playerPage['content'] = {
contentData: {
@@ -874,19 +1201,31 @@ describe('PlayerPage', () => {
};
const event = {
edata: {
- type: 'DOWNLOAD'
+ type: 'PRINT'
}
};
- mockCommonUtilService.showToast = jest.fn();
- mockDownloadPdfService.downloadPdf = jest.fn(() => Promise.reject({
- reason: 'device-permission-denied'
- }));
+ mockprintPdfService.printPdf = jest.fn()
playerPage.playerEvents(event);
setTimeout(() => {
expect(mockDownloadPdfService.downloadPdf).toHaveBeenCalled();
- // expect(CommonUtilService.showToast).toHaveBeenCalledWith('DEVICE_NEEDS_PERMISSION');
}, 0);
+ });
+ it('should call the print service to print the pdf for catch part', () => {
+ mockAppGlobalService.getCurrentUser = jest.fn(() => ({ uid: 'sample-uid' }));
+ playerPage['content'] = {
+ contentData: {
+ downloadUrl: 'https://'
+ }
+ };
+ const event = {
+ edata: {
+ type: 'NEXT_CONTENT_PLAY'
+ }
+ };
+ playerPage.playerEvents(event);
+ setTimeout(() => {
+ }, 0);
});
it('should call the download service to download the pdf for catch part(user-permission-denied)', () => {
mockAppGlobalService.getCurrentUser = jest.fn(() => ({ uid: 'sample-uid' }));
@@ -957,7 +1296,7 @@ describe('PlayerPage', () => {
type: 'compatibility-error'
}
};
- global.window.cordova.plugins.InAppUpdateManager.checkForImmediateUpdate = jest.fn(() => { });
+ global.window.cordova.plugins.InAppUpdateManager.checkForImmediateUpdate = jest.fn((fn, fn1) => {fn({ }), fn1({})});
playerPage.playerEvents(event);
setTimeout(() => {
expect(global.window.cordova.plugins.InAppUpdateManager.checkForImmediateUpdate).toHaveBeenCalled();
@@ -977,6 +1316,19 @@ describe('PlayerPage', () => {
expect(mockCommonUtilService.handleAssessmentStatus).toHaveBeenCalled();
});
+ it('should handle the exdata event if no curent attemopts', () => {
+ mockAppGlobalService.getCurrentUser = jest.fn(() => ({ uid: 'sample-uid' }));
+ const event = {
+ edata: {
+ type: 'exdata',
+ currentattempt: 0,
+ maxLimitExceeded: false,
+ isLastAttempt: false,
+ }
+ };
+ playerPage.playerEvents(event);
+ });
+
it('should handle the DEVICE_ROTATION_CLICKED event', () => {
mockAppGlobalService.getCurrentUser = jest.fn(() => ({ uid: 'sample-uid' }));
const event = {
@@ -990,6 +1342,27 @@ describe('PlayerPage', () => {
playerPage.playerEvents(event);
});
+
+ it('should handle if no event edata type', () => {
+ mockAppGlobalService.getCurrentUser = jest.fn(() => ({ uid: 'sample-uid' }));
+ const event = {
+ edata: {
+ type: ''
+ }
+ };
+ // act
+ playerPage.playerEvents(event);
+
+ });
+ it('should handle if no event edata', () => {
+ mockAppGlobalService.getCurrentUser = jest.fn(() => ({ uid: 'sample-uid' }));
+ const event = {
+ edata: ''
+ };
+ // act
+ playerPage.playerEvents(event);
+
+ });
});
describe('ngOnDestroy', () => {
@@ -997,85 +1370,603 @@ describe('PlayerPage', () => {
// arrange
playerPage['pauseSubscription'] = {
unsubscribe: jest.fn(),
-
} as any;
// act
playerPage.ngOnDestroy();
// assert
expect(playerPage['pauseSubscription'].unsubscribe).toHaveBeenCalled();
});
-
+ it('should handle else if no pauseSubscription', () => {
+ // arrange
+ playerPage['pauseSubscription'] = undefined as any;
+ // act
+ playerPage.ngOnDestroy();
+ // assert
+ });
});
- describe('ionViewWillLeave', () => {
- it('should unsubscribe backButtonSubscription', () => {
- // arrange
- mockStatusBar.show = jest.fn();
- mockSharedPreferences.getString = jest.fn(() => of("Orientation"));
- mockScreenOrientation.unlock = jest.fn();
- playerPage['events'] = {
- unsubscribe: jest.fn(),
- } as any;
- playerPage['backButtonSubscription'] = {
- unsubscribe: jest.fn(),
- } as any;
- // act
- playerPage.ionViewWillLeave();
- // assert
- setTimeout(() => {
- expect(playerPage['events'].unsubscribe).toHaveBeenCalled();
- expect(playerPage['backButtonSubscription'].unsubscribe).toHaveBeenCalled();
- expect(mockStatusBar.show).toHaveBeenCalled();
- expect( mockScreenOrientation.unlock).toHaveBeenCalled();
- }, 100);;
- });
-
- it('should unsubscribe backButtonSubscription', () => {
- // arrange
- mockStatusBar.show = jest.fn();
- mockSharedPreferences.getString = jest.fn(() => of("Landscape"));
- mockScreenOrientation.unlock = jest.fn();
- playerPage['events'] = {
- unsubscribe: jest.fn(),
- } as any;
- playerPage['backButtonSubscription'] = {
- unsubscribe: jest.fn(),
- } as any;
- // act
- playerPage.ionViewWillLeave();
- // assert
- setTimeout(() => {
- expect(playerPage['events'].unsubscribe).toHaveBeenCalled();
- expect(playerPage['backButtonSubscription'].unsubscribe).toHaveBeenCalled();
- expect(mockStatusBar.show).toHaveBeenCalled();
- expect( mockScreenOrientation.unlock).toHaveBeenCalled();
- }, 100);;
- });
- });
+ describe('ionViewWillLeave', () => {
+ it('should unsubscribe backButtonSubscription', () => {
+ // arrange
+ mockStatusBar.show = jest.fn();
+ mockSharedPreferences.getString = jest.fn(() => of("Orientation"));
+ mockScreenOrientation.unlock = jest.fn();
+ playerPage['events'] = {
+ unsubscribe: jest.fn(),
+ } as any;
+ playerPage['backButtonSubscription'] = {
+ unsubscribe: jest.fn(),
+ } as any;
+ // act
+ playerPage.ionViewWillLeave();
+ // assert
+ setTimeout(() => {
+ expect(playerPage['events'].unsubscribe).toHaveBeenCalled();
+ expect(playerPage['backButtonSubscription'].unsubscribe).toHaveBeenCalled();
+ expect(mockStatusBar.show).toHaveBeenCalled();
+ expect( mockScreenOrientation.unlock).toHaveBeenCalled();
+ }, 100);;
+ });
- describe('openPDF' , () =>{
- it('should create a loader and dismiss' , () =>{
- //arrange
- mockCommonUtilService.getLoader = jest.fn(() => Promise.resolve({
- present: jest.fn(),
- dismiss: jest.fn(() => Promise.resolve())
- }));
- mockTelemetryGeneratorService.generateErrorTelemetry = jest.fn();
- mockLocation.back = jest.fn();
- //act
- playerPage.openPDF("https://sample/openPdfUrl");
- //assert
- setTimeout(() => {
- expect(mockCommonUtilService.getLoader).toHaveBeenCalled();
- expect(mockTelemetryGeneratorService.generateErrorTelemetry).toHaveBeenCalledWith(
- Environment.PLAYER,
- TelemetryErrorCode.ERR_DOWNLOAD_FAILED,
- ErrorType.SYSTEM,
- PageId.PLAYER,
- JSON.stringify(e)
- );
- expect(mockLocation.back).toHaveBeenCalled();
- }, 0);
- } )
- })
+ it('should unsubscribe backButtonSubscription', () => {
+ // arrange
+ mockStatusBar.show = jest.fn();
+ mockSharedPreferences.getString = jest.fn(() => of("Landscape"));
+ mockScreenOrientation.unlock = jest.fn();
+ playerPage['events'] = undefined as any;
+ playerPage['backButtonSubscription'] = undefined as any;
+ window.removeEventListener = jest.fn((_,fn) => fn({}))
+ // act
+ playerPage.ionViewWillLeave();
+ // assert
+ setTimeout(() => {
+ // expect(playerPage['events'].unsubscribe).toHaveBeenCalled();
+ // expect(playerPage['backButtonSubscription'].unsubscribe).toHaveBeenCalled();
+ expect(mockStatusBar.show).toHaveBeenCalled();
+ expect( mockScreenOrientation.unlock).toHaveBeenCalled();
+ }, 100);;
+ });
+ });
+
+ describe('openPDF' , () =>{
+ it('should create a loader and dismiss' , async () =>{
+ //arrange
+ playerPage.previewElement= {
+ nativeElement: {
+ contentWindow: {
+ EkstepRendererAPI : {
+ getCurrentStageId: jest.fn()
+ },
+ TelemetryService:{
+ exit: jest.fn(),
+ interact: jest.fn()
+ },
+ Renderer : {
+ running: true
+ }
+ }
+ }
+ }
+ playerPage.config = {
+ context: {
+ actor: {id: 'some_id'}
+ },
+ metadata: {
+ identifier: 'id'
+ }
+ }
+ const course = {
+ identifier: 'id',
+ batchId: '12',
+ courseId: '324'
+ }
+ const updateContentStateRequest: UpdateContentStateRequest = {
+ userId: playerPage.config['context']['actor']['id'],
+ contentId: playerPage.config['metadata']['identifier'],
+ courseId: course['identifier'] || course['courseId'],
+ batchId: course['batchId'],
+ status: 2,
+ progress: 100,
+ target: [UpdateContentStateTarget.LOCAL, UpdateContentStateTarget.SERVER]
+ };
+ mockCourseService.updateContentState = jest.fn(() => of({}))
+ window.setTimeout = jest.fn((fn) => {
+ fn()
+ }, 1000) as any;
+ mockCommonUtilService.getLoader = jest.fn(() => Promise.resolve({
+ present: jest.fn(),
+ dismiss: jest.fn(() => Promise.resolve())
+ }));
+ mockTelemetryGeneratorService.generateErrorTelemetry = jest.fn();
+ mockLocation.back = jest.fn();
+ const mockDownload = jest.fn(() => Promise.resolve({
+ toURL: () => 'SOME_TEMP_URL'
+ }));
+ mockTransfer.create = jest.fn(() => {
+ return {
+ download: mockDownload
+ };
+ }) as any;
+ mockFileOpener.open = jest.fn(() => Promise.resolve())
+ mockLocation.back = jest.fn();
+ //act
+ playerPage.openPDF("https://sample/openPdfUrl");
+ //assert
+ setTimeout(() => {
+ // expect(mockCommonUtilService.getLoader).toHaveBeenCalled();
+ // expect(mockTelemetryGeneratorService.generateErrorTelemetry).toHaveBeenCalledWith(
+ // Environment.PLAYER,
+ // TelemetryErrorCode.ERR_DOWNLOAD_FAILED,
+ // ErrorType.SYSTEM,
+ // PageId.PLAYER,
+ // JSON.stringify('e')
+ // );
+ // expect(mockCourseService.updateContentState).toHaveBeenCalledWith(updateContentStateRequest);
+ // expect(mockLocation.back).toHaveBeenCalled();
+ }, 1000);
+ })
+
+ it('should create a loader and dismiss, handle error on file opener' , async () =>{
+ //arrange
+ playerPage.previewElement= {
+ nativeElement: {
+ contentWindow: {
+ EkstepRendererAPI : {
+ getCurrentStageId: jest.fn()
+ },
+ TelemetryService:{
+ exit: jest.fn(),
+ interact: jest.fn()
+ },
+ Renderer : {
+ running: true
+ }
+ }
+ }
+ }
+ mockCommonUtilService.getLoader = jest.fn(() => Promise.resolve({
+ present: jest.fn(),
+ dismiss: jest.fn(() => Promise.resolve())
+ }));
+ mockTelemetryGeneratorService.generateErrorTelemetry = jest.fn();
+ mockLocation.back = jest.fn();
+ const mockDownload = jest.fn(() => Promise.resolve({
+ toURL: () => 'SOME_TEMP_URL'
+ }));
+ mockTransfer.create = jest.fn(() => {
+ return {
+ download: mockDownload
+ };
+ }) as any;
+ mockFileOpener.open = jest.fn(() => Promise.reject())
+ mockLocation.back = jest.fn();
+ //act
+ playerPage.openPDF("https://sample/openPdfUrl");
+ //assert
+ setTimeout(() => {
+ expect(mockCommonUtilService.getLoader).toHaveBeenCalled();
+ expect(mockTelemetryGeneratorService.generateErrorTelemetry).toHaveBeenCalledWith(
+ Environment.PLAYER,
+ TelemetryErrorCode.ERR_DOWNLOAD_FAILED,
+ ErrorType.SYSTEM,
+ PageId.PLAYER,
+ JSON.stringify('e')
+ );
+ expect(mockLocation.back).toHaveBeenCalled();
+ }, 1000);
+ })
+ it('should create a loader and dismiss and handle error on download' , () =>{
+ //arrange
+ playerPage.previewElement= {
+ nativeElement: {
+ contentWindow: {
+ EkstepRendererAPI : {
+ getCurrentStageId: jest.fn()
+ },
+ TelemetryService:{
+ exit: jest.fn(() => Promise.reject()),
+ interact: jest.fn()
+ },
+ Renderer : {
+ running: true
+ }
+ }
+ }
+ }
+ mockCommonUtilService.getLoader = jest.fn(() => Promise.resolve({
+ present: jest.fn(),
+ dismiss: jest.fn(() => Promise.resolve())
+ }));
+ mockTelemetryGeneratorService.generateErrorTelemetry = jest.fn();
+ mockLocation.back = jest.fn();
+ const mockDownload = jest.fn(() => Promise.reject({
+ }));
+ mockTransfer.create = jest.fn(() => {
+ return {
+ download: mockDownload
+ };
+ }) as any;
+ mockFileOpener.open = jest.fn(() => Promise.reject({}))
+ mockCommonUtilService.showToast = jest.fn()
+ mockLocation.back = jest.fn();
+ //act
+ playerPage.openPDF("https://sample/openPdfUrl");
+ //assert
+ setTimeout(() => {
+ expect(mockCommonUtilService.getLoader).toHaveBeenCalled();
+ expect(mockTelemetryGeneratorService.generateErrorTelemetry).toHaveBeenCalledWith(
+ Environment.PLAYER,
+ TelemetryErrorCode.ERR_DOWNLOAD_FAILED,
+ ErrorType.SYSTEM,
+ PageId.PLAYER,
+ JSON.stringify(e)
+ );
+ expect(mockLocation.back).toHaveBeenCalled();
+ }, 0);
+ })
+ it('should create a loader and dismiss and handle error on exit telemetry service' , () =>{
+ //arrange
+ playerPage.course = '';
+ playerPage.previewElement= {
+ nativeElement: {
+ contentWindow: {
+ EkstepRendererAPI : {
+ getCurrentStageId: jest.fn()
+ },
+ TelemetryService:{
+ exit: jest.fn(() => Promise.reject({})),
+ interact: jest.fn()
+ },
+ Renderer : {
+ running: true
+ }
+ }
+ }
+ }
+ mockCommonUtilService.getLoader = jest.fn(() => Promise.resolve({
+ present: jest.fn(),
+ dismiss: jest.fn(() => Promise.resolve())
+ }));
+ mockTelemetryGeneratorService.generateErrorTelemetry = jest.fn();
+ mockLocation.back = jest.fn();
+ const mockDownload = jest.fn(() => Promise.reject({
+ }));
+ mockTransfer.create = jest.fn(() => {
+ return {
+ download: mockDownload
+ };
+ }) as any;
+ mockFileOpener.open = jest.fn(() => Promise.resolve())
+ mockLocation.back = jest.fn();
+ //act
+ playerPage.openPDF("https://sample/openPdfUrl");
+ //assert
+ setTimeout(() => {
+ expect(mockCommonUtilService.getLoader).toHaveBeenCalled();
+ expect(mockTelemetryGeneratorService.generateErrorTelemetry).toHaveBeenCalledWith(
+ Environment.PLAYER,
+ TelemetryErrorCode.ERR_DOWNLOAD_FAILED,
+ ErrorType.SYSTEM,
+ PageId.PLAYER,
+ JSON.stringify('e')
+ );
+ expect(mockLocation.back).toHaveBeenCalled();
+ }, 0);
+ })
+ })
+
+ xdescribe('onContentNotFound', () => {
+ it('should check Content on NotFound', (done) => {
+ // arrange
+ const info: Array = [{identifier: 'abc',
+ contentType: '',
+ primaryCategory: ''}];
+ const content = {identifier:'', info};
+ window.setTimeout = jest.fn((fn) => {
+ fn();
+ }, 1000) as any;
+ jest.spyOn(playerPage, 'closeIframe').mockImplementation();
+ mockEvents.publish = jest.fn(() => Promise.resolve())
+ // act
+ playerPage.onContentNotFound('', info);
+ // asert
+ setTimeout(() => {
+ playerPage.closeIframe();
+ done()
+ }, 0);
+ expect(mockEvents.publish).toHaveBeenCalledWith(EventTopics.NEXT_CONTENT, {
+ content,
+ course: playerPage.course
+ });
+ })
+ })
+
+ describe('onUserSwitch', () => {
+ it('should switch user', () => {
+ // arrange
+ const user: User = {
+ uid: ''
+ };
+ mockAppGlobalService.setSelectedUser = jest.fn();
+ // act
+ playerPage.onUserSwitch(user);
+ // asert
+ expect(mockAppGlobalService.setSelectedUser).toHaveBeenCalledWith(user)
+ })
+ })
+
+ describe('closeIframe', () => {
+ it('should closeIframe', () => {
+ // arrange
+ const content = {ContentData: {downloadUrl:''}}
+ playerPage.previewElement = {
+ nativeElement: {
+ contentWindow: {
+ EkstepRendererAPI: {
+ getCurrentStageId: jest.fn()
+ },
+ TelemetryService: {
+ exit: jest.fn()
+ }
+ }
+ }
+ }
+ playerPage['navigateBackToContentDetails'] = true;
+ mockAppGlobalService.getSelectedUser = jest.fn(() => Promise.resolve())
+ mockEvents.publish = jest.fn();
+ mockRouter.navigate = jest.fn(() => Promise.resolve()) as any;
+ // act
+ setTimeout(() => {
+ playerPage.closeIframe(content);
+ // asert
+ expect(mockEvents.publish).toHaveBeenCalled();
+ }, 1000);
+ })
+
+ it('should closeIframe and error on exit telemetry services', () => {
+ // arrange
+ const content = {ContentData: {downloadUrl:''}}
+ playerPage.previewElement = {
+ nativeElement: {
+ contentWindow: {
+ EkstepRendererAPI: {
+ getCurrentStageId: jest.fn()
+ },
+ TelemetryService: {
+ exit: jest.fn(() => Promise.reject({}))
+ }
+ }
+ }
+ }
+ playerPage['navigateBackToContentDetails'] = false;
+ playerPage['navigateBackToTrackableCollection'] = true;
+ mockAppGlobalService.getSelectedUser = jest.fn(() => Promise.resolve())
+ mockEvents.publish = jest.fn();
+ mockRouter.navigate = jest.fn(() => Promise.resolve()) as any;
+ // act
+ setTimeout(() => {
+ playerPage.closeIframe(content);
+ // asert
+ expect(mockEvents.publish).toHaveBeenCalled();
+ }, 1000);
+ })
+
+ it('should go back to last location if not trackable or content details', () => {
+ // arrange
+ const content = {ContentData: {downloadUrl:''}}
+ playerPage.previewElement = {
+ nativeElement: {
+ contentWindow: {
+ EkstepRendererAPI: {
+ getCurrentStageId: jest.fn()
+ },
+ TelemetryService: {
+ exit: jest.fn(() => Promise.reject({}))
+ }
+ }
+ }
+ }
+ playerPage['navigateBackToContentDetails'] = false;
+ playerPage['navigateBackToTrackableCollection'] = false;
+ mockAppGlobalService.getSelectedUser = jest.fn(() => Promise.resolve())
+ mockEvents.publish = jest.fn();
+ mockLocation.back = jest.fn(() => Promise.resolve());
+ // act
+ setTimeout(() => {
+ playerPage.closeIframe(content);
+ // asert
+ expect(mockEvents.publish).toHaveBeenCalled();
+ expect(mockLocation.back).toHaveBeenCalled();
+ }, 1000);
+ })
+ })
+
+ describe('playerTelemetryEvents', () => {
+ it('should handle playerTelemetryEvents', () => {
+ // arrange
+ jest.spyOn(SunbirdSdk, 'instance', 'get').mockReturnValue({
+ telemetryService: {
+ saveTelemetry(request: string): Observable {
+ // for success
+ return of(true);
+ // for error
+ return throwError(new Error('sample_error'));
+ }
+ } as Partial as TelemetryService
+ } as Partial as SunbirdSdk);
+ // act
+ playerPage.playerTelemetryEvents({});
+ // assert
+ })
+
+ it('should handle playerTelemetryEvents on else case no events', () => {
+ // arrange
+ let event = undefined;
+ mockTelemetryService.saveTelemetry = jest.fn(() => of());
+ // act
+ playerPage.playerTelemetryEvents(event);
+ // assert
+ })
+ })
+
+ describe('handleDownload', () => {
+ it('should handleDownload ', () => {
+ // arrange
+ mockDownloadPdfService.downloadPdf = jest.fn(() => Promise.resolve('res'))
+ mockCommonUtilService.showToast = jest.fn();
+ // act
+ playerPage.handleDownload();
+ // assert
+ setTimeout(() => {
+ expect(mockDownloadPdfService.downloadPdf).toHaveBeenCalled()
+ expect(mockCommonUtilService.showToast).toHaveBeenCalledWith('CONTENT_DOWNLOADED');
+ }, 0);
+ })
+
+ it('should handleDownload and handle error on downlaod pdf ', () => {
+ // arrange
+ mockDownloadPdfService.downloadPdf = jest.fn(() => Promise.reject({reason: 'device-permission-denied'}))
+ mockCommonUtilService.showToast = jest.fn();
+ // act
+ playerPage.handleDownload();
+ // assert
+ setTimeout(() => {
+ expect(mockDownloadPdfService.downloadPdf).toHaveBeenCalled()
+ expect(mockCommonUtilService.showToast).toHaveBeenCalledWith('CONTENT_DOWNLOADED');
+ }, 0);
+ })
+
+ it('should handleDownload and handle empty error on downlaod pdf ', () => {
+ // arrange
+ mockDownloadPdfService.downloadPdf = jest.fn(() => Promise.reject({reason: ''}))
+ mockCommonUtilService.showToast = jest.fn();
+ // act
+ playerPage.handleDownload();
+ // assert
+ setTimeout(() => {
+ expect(mockDownloadPdfService.downloadPdf).toHaveBeenCalled()
+ expect(mockCommonUtilService.showToast).toHaveBeenCalledWith('CONTENT_DOWNLOADED');
+ }, 0);
+ })
+ it('should handleDownload for ios platform ', () => {
+ // arrange
+ mockPlatform.is = jest.fn((platform) => platform === "ios");
+ mockFile.checkDir = jest.fn(() => Promise.resolve()) as any;
+ mockFile.checkFile = jest.fn(() => Promise.resolve()) as any;
+ mockCommonUtilService.showToast = jest.fn();
+ // act
+ playerPage.handleDownload();
+ // assert
+ setTimeout(() => {
+ expect(mockDownloadPdfService.downloadPdf).toHaveBeenCalled()
+ expect(mockCommonUtilService.showToast).toHaveBeenCalledWith('CONTENT_DOWNLOADED');
+ }, 0);
+ })
+
+ it('should handleDownload for ios platform checkfile error and downlaod file for ios', () => {
+ // arrange
+ mockPlatform.is = jest.fn((platform) => platform === "ios");
+ mockFile.checkDir = jest.fn(() => Promise.resolve()) as any;
+ mockFile.checkFile = jest.fn(() => Promise.reject()) as any;
+ mockCommonUtilService.showToast = jest.fn();
+ // act
+ playerPage.handleDownload();
+ // assert
+ setTimeout(() => {
+ expect(mockDownloadPdfService.downloadPdf).toHaveBeenCalled()
+ expect(mockCommonUtilService.showToast).toHaveBeenCalledWith('CONTENT_DOWNLOADED');
+ }, 500);
+ })
+
+ it('should handleDownload for ios platform checkdir error and downlaod file for ios', () => {
+ // arrange
+ mockPlatform.is = jest.fn((platform) => platform === "ios");
+ mockFile.checkDir = jest.fn(() => Promise.reject()) as any;
+ mockFile.createDir = jest.fn(() => Promise.resolve({})) as any;
+ mockCommonUtilService.showToast = jest.fn();
+ // act
+ playerPage.handleDownload();
+ // assert
+ setTimeout(() => {
+ expect(mockDownloadPdfService.downloadPdf).toHaveBeenCalled()
+ expect(mockCommonUtilService.showToast).toHaveBeenCalledWith('CONTENT_DOWNLOADED');
+ }, 500);
+ })
+
+ it('should handleDownload for ios platform handle error on createdir and downlaod file for ios', () => {
+ // arrange
+ mockPlatform.is = jest.fn((platform) => platform === "ios");
+ mockFile.checkDir = jest.fn(() => Promise.reject()) as any;
+ mockFile.createDir = jest.fn(() => Promise.reject({})) as any;
+ mockCommonUtilService.showToast = jest.fn();
+ // act
+ playerPage.handleDownload();
+ // assert
+ setTimeout(() => {
+ expect(mockDownloadPdfService.downloadPdf).toHaveBeenCalled()
+ expect(mockCommonUtilService.showToast).toHaveBeenCalledWith('CONTENT_DOWNLOADED');
+ }, 500);
+ })
+ it('should show toast if no downlaod url', () => {
+ // arrange
+ playerPage['content'] = {
+ contentData: {
+ downloadUrl: ''
+ }
+ }
+ mockCommonUtilService.showToast = jest.fn();
+ // act
+ playerPage.handleDownload();
+ // assert
+ expect(mockCommonUtilService.showToast).toHaveBeenCalled();
+ })
+ })
+
+ describe('downloadFileIos', () => {
+ it('should download File for Ios', () => {
+ // arrange
+ const content = {contentData: {downloadUrl: ""}}
+ mockFile.documentsDirectory = '/'
+ const mockDownload = jest.fn(() => Promise.resolve({
+ toURL: () => 'SOME_TEMP_URL'
+ }));
+ window.setTimeout = jest.fn((fn) => {
+ fn()
+ }, 500) as any;
+ mockTransfer.create = jest.fn(() => {
+ return {
+ download: mockDownload
+ };
+ }) as any
+ mockCommonUtilService.showToast = jest.fn(() => Promise.resolve())
+ // act
+ playerPage.downloadFileIos(content);
+ // assert
+ setTimeout(() => {
+ expect(mockTransfer.create).toHaveBeenCalled();
+ }, 500);
+ })
+
+ it('should download File for Ios handle error', () => {
+ // arrange
+ const content = {contentData: {downloadUrl: ""}}
+ mockFile.documentsDirectory = '/'
+ const mockDownload = jest.fn(() => Promise.reject({}));
+ window.setTimeout = jest.fn((fn) => {
+ fn()
+ }, 500) as any;
+ mockTransfer.create = jest.fn(() => {
+ return {
+ download: mockDownload
+ };
+ }) as any
+ mockCommonUtilService.showToast = jest.fn(() => Promise.resolve())
+ // act
+ playerPage.downloadFileIos(content);
+ // assert
+ setTimeout(() => {
+ expect(mockTransfer.create).toHaveBeenCalled();
+ }, 500);
+ })
+ })
});
diff --git a/src/app/player/player.page.ts b/src/app/player/player.page.ts
index 1af0e650f1..2d1ccddfcc 100644
--- a/src/app/player/player.page.ts
+++ b/src/app/player/player.page.ts
@@ -33,6 +33,7 @@ import { FileTransfer, FileTransferObject } from '@ionic-native/file-transfer/ng
import { ContentUtil } from '@app/util/content-util';
import { PrintPdfService } from '@app/services/print-pdf/print-pdf.service';
import { FormConstants } from '../form.constants';
+import { File } from '@ionic-native/file/ngx';
declare const cordova;
@@ -85,7 +86,8 @@ export class PlayerPage implements OnInit, OnDestroy, PlayerActionHandlerDelegat
private fileOpener: FileOpener,
private transfer: FileTransfer,
private telemetryGeneratorService: TelemetryGeneratorService,
- private printPdfService: PrintPdfService
+ private printPdfService: PrintPdfService,
+ private file: File,
) {
this.canvasPlayerService.handleAction();
@@ -127,7 +129,9 @@ export class PlayerPage implements OnInit, OnDestroy, PlayerActionHandlerDelegat
this.config['metadata']['children'] = (await this.contentService.getQuestionSetChildren(this.config['metadata']['identifier']))
this.playerType = 'sunbird-quml-player';
} else if(["video/mp4", "video/webm"].includes(this.config['metadata']['mimeType']) && this.checkIsPlayerEnabled(this.playerConfig , 'videoPlayer').name === "videoPlayer"){
- this.screenOrientation.lock(this.screenOrientation.ORIENTATIONS.LANDSCAPE);
+ if(!this.platform.is('ios')){
+ this.screenOrientation.lock(this.screenOrientation.ORIENTATIONS.LANDSCAPE);
+ }
this.config = await this.getNewPlayerConfiguration();
this.config['config'].sideMenu.showPrint = false;
this.playerType = 'sunbird-video-player';
@@ -283,6 +287,10 @@ export class PlayerPage implements OnInit, OnDestroy, PlayerActionHandlerDelegat
}
+ handleNavBackButton() {
+ this.showConfirm();
+ }
+
async playerEvents(event) {
if (event.edata) {
const userId: string = this.appGlobalService.getCurrentUser().uid;
@@ -317,21 +325,7 @@ export class PlayerPage implements OnInit, OnDestroy, PlayerActionHandlerDelegat
});
await popover.present();
} else if (event.edata['type'] === 'DOWNLOAD') {
- if (this.content.contentData.downloadUrl) {
- this.downloadPdfService.downloadPdf(this.content).then((res) => {
- this.commonUtilService.showToast('CONTENT_DOWNLOADED');
- }).catch((error) => {
- if (error.reason === 'device-permission-denied') {
- this.commonUtilService.showToast('DEVICE_NEEDS_PERMISSION');
- } else if (error.reason === 'user-permission-denied') {
- this.commonUtilService.showToast('DEVICE_NEEDS_PERMISSION');
- } else if (error.reason === 'download-failed') {
- this.commonUtilService.showToast('SOMETHING_WENT_WRONG');
- }
- });
- } else {
- this.commonUtilService.showToast('ERROR_CONTENT_NOT_AVAILABLE');
- }
+ this.handleDownload();
} else if (event.edata['type'] === 'PRINT') {
this.printPdfService.printPdf(this.config['metadata'].streamingUrl);
} else if(event.edata.type === 'NEXT_CONTENT_PLAY') {
@@ -355,6 +349,58 @@ export class PlayerPage implements OnInit, OnDestroy, PlayerActionHandlerDelegat
}
}
+ handleDownload() {
+ if (this.content.contentData.downloadUrl) {
+ if (this.platform.is('ios')) {
+ this.file.checkDir(this.file.documentsDirectory, 'downloads')
+ .then(() => {
+ this.file.checkFile(this.file.documentsDirectory, 'downloads/' + this.content.name + '.pdf')
+ .then(_ => {this.commonUtilService.showToast("A file with the same name already exists!")})
+ .catch(() => {
+ this.downloadFileIos(this.content);
+ })
+ })
+ .catch(() => {
+ this.file.createDir(this.file.documentsDirectory, 'downloads', false)
+ .then(response => {
+ this.downloadFileIos(this.content);
+ })
+ .catch((err) => {
+ this.commonUtilService.showToast('Error saving file: ' + err.message, false, 'redErrorToast');
+ })
+ })
+ } else { // android
+ this.downloadPdfService.downloadPdf(this.content).then((res) => {
+ this.commonUtilService.showToast('CONTENT_DOWNLOADED');
+ }).catch((error) => {
+ if (error.reason === 'device-permission-denied') {
+ this.commonUtilService.showToast('DEVICE_NEEDS_PERMISSION');
+ } else if (error.reason === 'user-permission-denied') {
+ this.commonUtilService.showToast('DEVICE_NEEDS_PERMISSION');
+ } else if (error.reason === 'download-failed') {
+ this.commonUtilService.showToast('SOMETHING_WENT_WRONG');
+ }
+ });
+ }
+ } else {
+ this.commonUtilService.showToast('ERROR_CONTENT_NOT_AVAILABLE');
+ }
+ }
+
+ downloadFileIos(content) {
+ const path = this.file.documentsDirectory;
+ const fileUri = content.contentData.downloadUrl;
+ const fileName = content.name;
+ setTimeout(() => {
+ const transfer = this.transfer.create();
+ transfer.download(fileUri, path + 'downloads/' + fileName + '.pdf').then(entry => {
+ this.commonUtilService.showToast('CONTENT_DOWNLOADED');
+ }).catch(err => {
+ this.commonUtilService.showToast('SOMETHING_WENT_WRONG');
+ });
+ },500)
+ }
+
async getNewPlayerConfiguration() {
const nextContent = this.config['metadata'].hierarchyInfo && this.nextContentToBePlayed ? { name: this.nextContentToBePlayed.contentData.name, identifier: this.nextContentToBePlayed.contentData.identifier } : undefined;
this.config['context']['pdata']['pid'] = 'sunbird.app.contentplayer';
diff --git a/src/app/profile-settings/profile-settings.page.html b/src/app/profile-settings/profile-settings.page.html
index 3db2dc050b..31dfcac3e2 100644
--- a/src/app/profile-settings/profile-settings.page.html
+++ b/src/app/profile-settings/profile-settings.page.html
@@ -1,7 +1,7 @@