Merge pull request #3825 from crazyserver/MOBILE-4362

Mobile 4362
main
Noel De Martin 2023-10-19 14:10:12 +02:00 committed by GitHub
commit 4e210350e5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 171 additions and 122 deletions

View File

@ -22,7 +22,7 @@ const THRESHOLD = .15; // % of the scroll element height that must be close to t
* Component to show a infinite loading trigger and spinner while more data is being loaded. * Component to show a infinite loading trigger and spinner while more data is being loaded.
* *
* Usage: * Usage:
* <core-infinite-loading [action]="loadingAction" [enabled]="dataLoaded"></core-inifinite-loading> * <core-infinite-loading [action]="loadingAction" [enabled]="dataLoaded"></core-infinite-loading>
*/ */
@Component({ @Component({
selector: 'core-infinite-loading', selector: 'core-infinite-loading',

View File

@ -21,7 +21,7 @@
<div *ngIf="selectedSection && selectedSection.id == allSectionsId"> <div *ngIf="selectedSection && selectedSection.id == allSectionsId">
<core-dynamic-component [component]="allSectionsComponent" [data]="data"> <core-dynamic-component [component]="allSectionsComponent" [data]="data">
<ng-container *ngFor="let section of sections; index as i"> <ng-container *ngFor="let section of sections; index as i">
<ng-container *ngIf="i <= showSectionId"> <ng-container *ngIf="i <= lastShownSectionIndex">
<ng-container *ngTemplateOutlet="sectionTemplate; context: {section: section}"></ng-container> <ng-container *ngTemplateOutlet="sectionTemplate; context: {section: section}"></ng-container>
</ng-container> </ng-container>
</ng-container> </ng-container>

View File

@ -70,7 +70,7 @@ import { CoreBlockSideBlocksComponent } from '@features/block/components/side-bl
}) })
export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy { export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy {
static readonly LOAD_MORE_ACTIVITIES = 20; // How many activities should load each time showMoreActivities is called. static readonly LOAD_MORE_ACTIVITIES = 10; // How many activities should load each time showMoreActivities is called.
@Input() course!: CoreCourseAnyCourseData; // The course to render. @Input() course!: CoreCourseAnyCourseData; // The course to render.
@Input() sections: CoreCourseSectionToDisplay[] = []; // List of course sections. @Input() sections: CoreCourseSectionToDisplay[] = []; // List of course sections.
@ -89,7 +89,7 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy {
allSectionsComponent?: Type<unknown>; allSectionsComponent?: Type<unknown>;
canLoadMore = false; canLoadMore = false;
showSectionId = 0; lastShownSectionIndex = 0;
data: Record<string, unknown> = {}; // Data to pass to the components. data: Record<string, unknown> = {}; // Data to pass to the components.
courseIndexTour: CoreUserTourDirectiveOptions = { courseIndexTour: CoreUserTourDirectiveOptions = {
id: 'course-index', id: 'course-index',
@ -514,8 +514,7 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy {
} else { } else {
this.previousSection = undefined; this.previousSection = undefined;
this.nextSection = undefined; this.nextSection = undefined;
this.canLoadMore = false; this.lastShownSectionIndex = -1;
this.showSectionId = 0;
this.showMoreActivities(); this.showMoreActivities();
} }
@ -594,40 +593,22 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy {
* @param infiniteComplete Infinite scroll complete function. Only used from core-infinite-loading. * @param infiniteComplete Infinite scroll complete function. Only used from core-infinite-loading.
*/ */
showMoreActivities(infiniteComplete?: () => void): void { showMoreActivities(infiniteComplete?: () => void): void {
this.canLoadMore = false;
const sections = this.sections || [];
let modulesLoaded = 0; let modulesLoaded = 0;
let i: number; while (this.lastShownSectionIndex < this.sections.length - 1 &&
for (i = this.showSectionId + 1; i < sections.length; i++) { modulesLoaded < CoreCourseFormatComponent.LOAD_MORE_ACTIVITIES) {
if (!sections[i].hasContent || !sections[i].modules) { this.lastShownSectionIndex++;
if (!this.sections[this.lastShownSectionIndex].hasContent || !this.sections[this.lastShownSectionIndex].modules) {
continue; continue;
} }
modulesLoaded += sections[i].modules.reduce((total, module) => modulesLoaded += this.sections[this.lastShownSectionIndex].modules.reduce((total, module) =>
!CoreCourseHelper.isModuleStealth(module, sections[i]) ? total + 1 : total, 0); !CoreCourseHelper.isModuleStealth(module, this.sections[this.lastShownSectionIndex]) ? total + 1 : total, 0);
if (modulesLoaded >= CoreCourseFormatComponent.LOAD_MORE_ACTIVITIES) {
break;
}
} }
this.showSectionId = i; this.canLoadMore = this.lastShownSectionIndex < this.sections.length - 1;
this.canLoadMore = i < sections.length;
if (this.canLoadMore) { infiniteComplete?.();
// Check if any of the following sections have any content.
let thereAreMore = false;
for (i++; i < sections.length; i++) {
if (sections[i].hasContent && sections[i].modules && sections[i].modules?.length > 0) {
thereAreMore = true;
break;
}
}
this.canLoadMore = thereAreMore;
}
infiniteComplete && infiniteComplete();
} }
/** /**

View File

@ -28,7 +28,7 @@
{{ 'core.course.hiddenfromstudents' | translate }} {{ 'core.course.hiddenfromstudents' | translate }}
</ion-badge> </ion-badge>
<ion-badge color="secondary" *ngIf="module.visible !== 0 && module.isStealth" class="ion-text-wrap"> <ion-badge color="secondary" *ngIf="module.visible !== 0 && module.isStealth" class="ion-text-wrap">
<ion-icon name="fas-low-vision" aria-hidden="true"></ion-icon> <ion-icon name="fas-eye-low-vision" aria-hidden="true"></ion-icon>
{{ 'core.course.hiddenoncoursepage' | translate }} {{ 'core.course.hiddenoncoursepage' | translate }}
</ion-badge> </ion-badge>
</div> </div>
@ -80,14 +80,14 @@
<!-- Description and restrictions --> <!-- Description and restrictions -->
<div *ngIf="module.description || module.availabilityinfo" id="activity-{{module.id}}-collapsible" <div *ngIf="module.description || (showAvailability && module.availabilityinfo)" id="activity-{{module.id}}-collapsible"
class="ion-text-wrap activity-description-availabilityinfo activity-extra" [collapsible-item]="64"> class="ion-text-wrap activity-description-availabilityinfo activity-extra" [collapsible-item]="64">
<core-format-text class="core-module-description" *ngIf="module.description" [text]="module.description" <core-format-text class="core-module-description" *ngIf="module.description" [text]="module.description"
contextLevel="module" [contextInstanceId]="module.id" [courseId]="module.course"> contextLevel="module" [contextInstanceId]="module.id" [courseId]="module.course">
</core-format-text> </core-format-text>
<!-- Availability info --> <!-- Availability info -->
<div *ngIf="module.availabilityinfo" class="core-module-availabilityinfo"> <div *ngIf="showAvailability && module.availabilityinfo" class="core-module-availabilityinfo">
<ion-icon name="fas-lock" [attr.aria-label]="'core.restricted' | translate"></ion-icon> <ion-icon name="fas-lock" [attr.aria-label]="'core.restricted' | translate"></ion-icon>
<core-format-text [text]="module.availabilityinfo" contextLevel="module" [contextInstanceId]="module.id" <core-format-text [text]="module.availabilityinfo" contextLevel="module" [contextInstanceId]="module.id"
[courseId]="module.course"> [courseId]="module.course">
@ -95,7 +95,7 @@
</div> </div>
</div> </div>
<div *ngIf="module.handlerData.extraBadge" class="ion-text-wrap activity-extrabadges activity-extra" <div *ngIf="showExtra && module.handlerData.extraBadge" class="ion-text-wrap activity-extrabadges activity-extra"
[innerHTML]="module.handlerData.extraBadge"></div> [innerHTML]="module.handlerData.extraBadge"></div>
</ion-label> </ion-label>

View File

@ -50,6 +50,11 @@ export class CoreCourseModuleComponent implements OnInit, OnDestroy {
@Input() showActivityDates = false; // Whether to show activity dates. @Input() showActivityDates = false; // Whether to show activity dates.
@Input() showCompletionConditions = false; // Whether to show activity completion conditions. @Input() showCompletionConditions = false; // Whether to show activity completion conditions.
@Input() showLegacyCompletion?: boolean; // Whether to show module completion in the old format. @Input() showLegacyCompletion?: boolean; // Whether to show module completion in the old format.
@Input() showCompletion = true; // Whether to show module completion.
@Input() showAvailability = true; // Whether to show module availability.
@Input() showExtra = true; // Whether to show extra badges.
@Input() showDownloadStatus = true; // Whether to show download status.
@Input() showIndentation = true; // Whether to show indentation
@Input() isLastViewed = false; // Whether it's the last module viewed in a course. @Input() isLastViewed = false; // Whether it's the last module viewed in a course.
@Output() completionChanged = new EventEmitter<CoreCourseModuleCompletionData>(); // Notify when module completion changes. @Output() completionChanged = new EventEmitter<CoreCourseModuleCompletionData>(); // Notify when module completion changes.
@HostBinding('class.indented') indented = false; @HostBinding('class.indented') indented = false;
@ -70,14 +75,24 @@ export class CoreCourseModuleComponent implements OnInit, OnDestroy {
*/ */
async ngOnInit(): Promise<void> { async ngOnInit(): Promise<void> {
const site = CoreSites.getRequiredCurrentSite(); const site = CoreSites.getRequiredCurrentSite();
const enableIndentation = await CoreCourse.isCourseIndentationEnabled(site, this.module.course);
this.indented = enableIndentation && this.module.indent > 0; if (this.showIndentation && this.module.indent > 0) {
this.indented = await CoreCourse.isCourseIndentationEnabled(site, this.module.course);
} else {
this.indented = false;
}
this.modNameTranslated = CoreCourse.translateModuleName(this.module.modname, this.module.modplural); this.modNameTranslated = CoreCourse.translateModuleName(this.module.modname, this.module.modplural);
if (this.showCompletion) {
this.showLegacyCompletion = this.showLegacyCompletion ?? this.showLegacyCompletion = this.showLegacyCompletion ??
CoreConstants.CONFIG.uselegacycompletion ?? CoreConstants.CONFIG.uselegacycompletion ??
!site.isVersionGreaterEqualThan('3.11'); !site.isVersionGreaterEqualThan('3.11');
this.checkShowCompletion(); this.checkShowCompletion();
} else {
this.showLegacyCompletion = false;
this.showCompletionConditions = false;
this.showManualCompletion = false;
this.hasCompletion = false;
}
if (!this.module.handlerData) { if (!this.module.handlerData) {
return; return;
@ -86,7 +101,7 @@ export class CoreCourseModuleComponent implements OnInit, OnDestroy {
this.module.handlerData.a11yTitle = this.module.handlerData.a11yTitle ?? this.module.handlerData.title; this.module.handlerData.a11yTitle = this.module.handlerData.a11yTitle ?? this.module.handlerData.title;
this.moduleHasView = CoreCourse.moduleHasView(this.module); this.moduleHasView = CoreCourse.moduleHasView(this.module);
if (this.module.handlerData?.showDownloadButton) { if (this.showDownloadStatus && this.module.handlerData.showDownloadButton) {
const status = await CoreCourseModulePrefetchDelegate.getModuleStatus(this.module, this.module.course); const status = await CoreCourseModulePrefetchDelegate.getModuleStatus(this.module, this.module.course);
this.updateModuleStatus(status); this.updateModuleStatus(status);

View File

@ -298,7 +298,7 @@ export class CoreCourseContentsPage implements OnInit, OnDestroy, CoreRefreshCon
await this.loadData(true, true); await this.loadData(true, true);
} finally { } finally {
// Do not call doRefresh on the format component if the refresher is defined in the format component // Do not call doRefresh on the format component if the refresher is defined in the format component
// to prevent an inifinite loop. // to prevent an infinite loop.
if (this.displayRefresher && this.formatComponent) { if (this.displayRefresher && this.formatComponent) {
await CoreUtils.ignoreErrors(this.formatComponent.doRefresh(refresher)); await CoreUtils.ignoreErrors(this.formatComponent.doRefresh(refresher));
} }

View File

@ -17,12 +17,24 @@
</core-empty-box> </core-empty-box>
<ion-list class="core-course-module-list-wrapper"> <ion-list class="core-course-module-list-wrapper">
<ng-container *ngFor="let section of sections"> <ng-container *ngFor="let section of sections; index as i">
<ng-container *ngIf="i <= lastShownSectionIndex">
<ion-item-divider class="course-section ion-text-wrap" *ngIf="section.name">
<ion-label>
<h2>
<core-format-text [text]="section.name" contextLevel="course" [contextInstanceId]="courseId">
</core-format-text>
</h2>
</ion-label>
</ion-item-divider>
<ng-container *ngFor="let module of section.modules"> <ng-container *ngFor="let module of section.modules">
<core-course-module *ngIf="module.visibleoncoursepage !== 0" [module]="module" [section]="section"> <core-course-module [module]="module" [section]="section" [showActivityDates]="false" [showAvailability]="false"
[showExtra]="false" [showDownloadStatus]="false" [showCompletion]="false" [showIndentation]="false">
</core-course-module> </core-course-module>
</ng-container> </ng-container>
</ng-container> </ng-container>
</ng-container>
</ion-list> </ion-list>
<core-infinite-loading [enabled]="canLoadMore" (action)="showMoreActivities($event)"></core-infinite-loading>
</core-loading> </core-loading>
</ion-content> </ion-content>

View File

@ -34,10 +34,14 @@ import { CoreAnalytics, CoreAnalyticsEventType } from '@services/analytics';
}) })
export class CoreCourseListModTypePage implements OnInit { export class CoreCourseListModTypePage implements OnInit {
private static readonly PAGE_LENGTH = 10; // How many activities should load each time showMoreActivities is called.
sections: CoreCourseSection[] = []; sections: CoreCourseSection[] = [];
title = ''; title = '';
loaded = false; loaded = false;
courseId?: number; courseId = 0;
canLoadMore = false;
lastShownSectionIndex = -1;
protected modName?: string; protected modName?: string;
protected archetypes: Record<string, number> = {}; // To speed up the check of modules. protected archetypes: Record<string, number> = {}; // To speed up the check of modules.
@ -64,9 +68,16 @@ export class CoreCourseListModTypePage implements OnInit {
* @inheritdoc * @inheritdoc
*/ */
async ngOnInit(): Promise<void> { async ngOnInit(): Promise<void> {
try {
this.title = CoreNavigator.getRouteParam('title') || ''; this.title = CoreNavigator.getRouteParam('title') || '';
this.courseId = CoreNavigator.getRouteNumberParam('courseId'); this.courseId = CoreNavigator.getRequiredRouteParam('courseId');
this.modName = CoreNavigator.getRouteParam('modName'); this.modName = CoreNavigator.getRequiredRouteParam('modName');
} catch (error) {
CoreDomUtils.showErrorModal(error);
CoreNavigator.back();
return;
}
try { try {
await this.fetchData(); await this.fetchData();
@ -77,8 +88,6 @@ export class CoreCourseListModTypePage implements OnInit {
/** /**
* Fetches the data. * Fetches the data.
*
* @returns Resolved when done.
*/ */
protected async fetchData(): Promise<void> { protected async fetchData(): Promise<void> {
if (!this.courseId) { if (!this.courseId) {
@ -90,12 +99,14 @@ export class CoreCourseListModTypePage implements OnInit {
let sections = await CoreCourse.getSections(this.courseId, false, true); let sections = await CoreCourse.getSections(this.courseId, false, true);
sections = sections.filter((section) => { sections = sections.filter((section) => {
if (!section.modules) { if (!section.modules.length || section.hiddenbynumsections) {
return false; return false;
} }
section.modules = section.modules.filter((mod) => { section.modules = section.modules.filter((mod) => {
if (!CoreCourseHelper.canUserViewModule(mod, section) || !CoreCourse.moduleHasView(mod)) { if (!CoreCourseHelper.canUserViewModule(mod, section) ||
!CoreCourse.moduleHasView(mod) ||
mod.visibleoncoursepage === 0) {
// Ignore this module. // Ignore this module.
return false; return false;
} }
@ -110,11 +121,11 @@ export class CoreCourseListModTypePage implements OnInit {
); );
} }
if (this.archetypes[mod.modname] == CoreConstants.MOD_ARCHETYPE_RESOURCE) { if (this.archetypes[mod.modname] === CoreConstants.MOD_ARCHETYPE_RESOURCE) {
return true; return true;
} }
} else if (mod.modname == this.modName) { } else if (mod.modname === this.modName) {
return true; return true;
} }
}); });
@ -125,19 +136,39 @@ export class CoreCourseListModTypePage implements OnInit {
const result = await CoreCourseHelper.addHandlerDataForModules(sections, this.courseId); const result = await CoreCourseHelper.addHandlerDataForModules(sections, this.courseId);
this.sections = result.sections; this.sections = result.sections;
this.lastShownSectionIndex = -1;
this.showMoreActivities();
} catch (error) { } catch (error) {
CoreDomUtils.showErrorModalDefault(error, 'Error getting data'); CoreDomUtils.showErrorModalDefault(error, 'Error getting data');
} }
} }
/**
* Show more activities.
*
* @param infiniteComplete Infinite scroll complete function. Only used from core-infinite-loading.
*/
showMoreActivities(infiniteComplete?: () => void): void {
let modulesLoaded = 0;
while (this.lastShownSectionIndex < this.sections.length - 1 && modulesLoaded < CoreCourseListModTypePage.PAGE_LENGTH) {
this.lastShownSectionIndex++;
modulesLoaded += this.sections[this.lastShownSectionIndex].modules.length;
}
this.canLoadMore = this.lastShownSectionIndex < this.sections.length - 1;
infiniteComplete?.();
}
/** /**
* Refresh the data. * Refresh the data.
* *
* @param refresher Refresher. * @param refresher Refresher.
* @returns Promise resolved when done.
*/ */
async refreshData(refresher: IonRefresher): Promise<void> { async refreshData(refresher: IonRefresher): Promise<void> {
await CoreUtils.ignoreErrors(CoreCourse.invalidateSections(this.courseId || 0)); await CoreUtils.ignoreErrors(CoreCourse.invalidateSections(this.courseId));
try { try {
await this.fetchData(); await this.fetchData();

View File

@ -40,7 +40,7 @@
{{ 'core.course.hiddenfromstudents' | translate }} {{ 'core.course.hiddenfromstudents' | translate }}
</ion-badge> </ion-badge>
<ion-badge color="secondary" *ngIf="module.visible !== 0 && module.isStealth" class="ion-text-wrap"> <ion-badge color="secondary" *ngIf="module.visible !== 0 && module.isStealth" class="ion-text-wrap">
<ion-icon name="fas-low-vision" aria-hidden="true"></ion-icon> <ion-icon name="fas-eye-low-vision" aria-hidden="true"></ion-icon>
{{ 'core.course.hiddenoncoursepage' | translate }} {{ 'core.course.hiddenoncoursepage' | translate }}
</ion-badge> </ion-badge>
</div> </div>

View File

@ -85,20 +85,20 @@ Feature: Test basic usage of one course in app
And I press "OK" in the app And I press "OK" in the app
And I wait loading to finish in the app And I wait loading to finish in the app
Then the header should be "Course 1" in the app Then the header should be "Course 1" in the app
And I should find "Test forum name" in the app
And I should find "Test wiki name" in the app
And I should find "Choice course 1" in the app And I should find "Choice course 1" in the app
And I should find "assignment" in the app And I should find "assignment" in the app
And I should find "Test forum name" in the app
And I should find "Test chat name" in the app
And I should find "Web links" in the app
And I should find "Test external name" in the app And I should find "Test external name" in the app
And I should find "Test feedback name" in the app
And I should find "Test glossary" in the app
And I should find "Quiz 1" in the app
And I should find "Test survey name" in the app And I should find "Test survey name" in the app
And I should find "Test wiki name" in the app And I should find "Test chat name" in the app
And I should find "Test lesson name" in the app And I should find "Quiz 1" in the app
And I should find "Test scorm name" in the app And I should find "Test scorm name" in the app
And I should find "Test feedback name" in the app
And I should find "Test lesson name" in the app
And I should find "Test workshop name" in the app And I should find "Test workshop name" in the app
And I should not find "Web links" in the app
And I should not find "Test glossary" in the app
Scenario: Guest access Scenario: Guest access
Given I entered the course "Course 1" as "teacher1" in the app Given I entered the course "Course 1" as "teacher1" in the app
@ -122,16 +122,16 @@ Feature: Test basic usage of one course in app
When I press "View course" "ion-button" in the app When I press "View course" "ion-button" in the app
Then the header should be "Course 1" in the app Then the header should be "Course 1" in the app
And I should find "Test forum name" in the app
And I should find "Test wiki name" in the app
And I should find "Choice course 1" in the app And I should find "Choice course 1" in the app
And I should find "assignment" in the app And I should find "assignment" in the app
And I should find "Test forum name" in the app
And I should find "Test chat name" in the app
And I should find "Web links" in the app
And I should find "Test feedback name" in the app
And I should find "Test glossary" in the app
And I should find "Quiz 1" in the app
And I should find "Test survey name" in the app And I should find "Test survey name" in the app
And I should find "Test wiki name" in the app And I should find "Test chat name" in the app
And I should find "Test lesson name" in the app And I should find "Quiz 1" in the app
And I should find "Test scorm name" in the app And I should find "Test scorm name" in the app
And I should find "Test feedback name" in the app
And I should find "Test lesson name" in the app
And I should find "Test workshop name" in the app And I should find "Test workshop name" in the app
And I should not find "Web links" in the app
And I should not find "Test glossary" in the app

View File

@ -83,25 +83,33 @@ Feature: Test basic usage of one course in app
Scenario: View course contents Scenario: View course contents
When I entered the course "Course 1" as "student1" in the app When I entered the course "Course 1" as "student1" in the app
Then the header should be "Course 1" in the app Then the header should be "Course 1" in the app
And I should find "Test forum name" in the app
And I should find "Test wiki name" in the app
And I should find "Choice course 1" in the app And I should find "Choice course 1" in the app
And I should find "assignment" in the app And I should find "assignment" in the app
And I should find "Test forum name" in the app
And I should find "Test chat name" in the app
And I should find "Web links" in the app
And I should find "Test external name" in the app And I should find "Test external name" in the app
And I should find "Test feedback name" in the app
And I should find "Test glossary" in the app
And I should find "Quiz 1" in the app
And I should find "Test survey name" in the app And I should find "Test survey name" in the app
And I should find "Test wiki name" in the app And I should find "Test chat name" in the app
And I should find "Test lesson name" in the app And I should find "Quiz 1" in the app
And I should find "Test scorm name" in the app And I should find "Test scorm name" in the app
And I should find "Test feedback name" in the app
And I should find "Test lesson name" in the app
And I should find "Test workshop name" in the app And I should find "Test workshop name" in the app
And I should not find "Web links" in the app
And I should not find "Test glossary" in the app
When I set "page-core-course-index .core-course-thumb" styles to "background" "lightblue" When I set "page-core-course-index .core-course-thumb" styles to "background" "lightblue"
And I set "page-core-course-index .core-course-thumb img" styles to "display" "none" And I set "page-core-course-index .core-course-thumb img" styles to "display" "none"
Then the UI should match the snapshot Then the UI should match the snapshot
# Test infinite scroll on course
When I scroll to "Test workshop name" in the app
Then I should find "Web links" in the app
And I should find "Test glossary" in the app
# Test Collapsible header
And the UI should match the snapshot
When I press "Choice course 1" in the app When I press "Choice course 1" in the app
Then the header should be "Choice course 1" in the app Then the header should be "Choice course 1" in the app
@ -161,20 +169,20 @@ Feature: Test basic usage of one course in app
Scenario: View section contents Scenario: View section contents
When I entered the course "Course 1" as "student1" in the app When I entered the course "Course 1" as "student1" in the app
Then the header should be "Course 1" in the app Then the header should be "Course 1" in the app
And I should find "Test forum name" in the app
And I should find "Test wiki name" in the app
And I should find "Choice course 1" in the app And I should find "Choice course 1" in the app
And I should find "assignment" in the app And I should find "assignment" in the app
And I should find "Test forum name" in the app
And I should find "Test chat name" in the app
And I should find "Web links" in the app
And I should find "Test external name" in the app And I should find "Test external name" in the app
And I should find "Test feedback name" in the app
And I should find "Test glossary" in the app
And I should find "Quiz 1" in the app
And I should find "Test survey name" in the app And I should find "Test survey name" in the app
And I should find "Test wiki name" in the app And I should find "Test chat name" in the app
And I should find "Test lesson name" in the app And I should find "Quiz 1" in the app
And I should find "Test scorm name" in the app And I should find "Test scorm name" in the app
And I should find "Test feedback name" in the app
And I should find "Test lesson name" in the app
And I should find "Test workshop name" in the app And I should find "Test workshop name" in the app
And I should not find "Web links" in the app
And I should not find "Test glossary" in the app
When I press "Course index" in the app When I press "Course index" in the app
And I press "General" in the app And I press "General" in the app
@ -337,20 +345,20 @@ Feature: Test basic usage of one course in app
Scenario: Navigation between sections using the bottom arrows Scenario: Navigation between sections using the bottom arrows
When I entered the course "Course 1" as "student1" in the app When I entered the course "Course 1" as "student1" in the app
Then the header should be "Course 1" in the app Then the header should be "Course 1" in the app
And I should find "Test forum name" in the app
And I should find "Test wiki name" in the app
And I should find "Choice course 1" in the app And I should find "Choice course 1" in the app
And I should find "assignment" in the app And I should find "assignment" in the app
And I should find "Test forum name" in the app
And I should find "Test chat name" in the app
And I should find "Web links" in the app
And I should find "Test external name" in the app And I should find "Test external name" in the app
And I should find "Test feedback name" in the app
And I should find "Test glossary" in the app
And I should find "Quiz 1" in the app
And I should find "Test survey name" in the app And I should find "Test survey name" in the app
And I should find "Test wiki name" in the app And I should find "Test chat name" in the app
And I should find "Test lesson name" in the app And I should find "Quiz 1" in the app
And I should find "Test scorm name" in the app And I should find "Test scorm name" in the app
And I should find "Test feedback name" in the app
And I should find "Test lesson name" in the app
And I should find "Test workshop name" in the app And I should find "Test workshop name" in the app
And I should not find "Web links" in the app
And I should not find "Test glossary" in the app
When I press "Course index" in the app When I press "Course index" in the app
And I press "General" in the app And I press "General" in the app
@ -425,20 +433,20 @@ Feature: Test basic usage of one course in app
And I press "OK" in the app And I press "OK" in the app
And I wait loading to finish in the app And I wait loading to finish in the app
Then the header should be "Course 1" in the app Then the header should be "Course 1" in the app
And I should find "Test forum name" in the app
And I should find "Test wiki name" in the app
And I should find "Choice course 1" in the app And I should find "Choice course 1" in the app
And I should find "assignment" in the app And I should find "assignment" in the app
And I should find "Test forum name" in the app
And I should find "Test chat name" in the app
And I should find "Web links" in the app
And I should find "Test external name" in the app And I should find "Test external name" in the app
And I should find "Test feedback name" in the app
And I should find "Test glossary" in the app
And I should find "Quiz 1" in the app
And I should find "Test survey name" in the app And I should find "Test survey name" in the app
And I should find "Test wiki name" in the app And I should find "Test chat name" in the app
And I should find "Test lesson name" in the app And I should find "Quiz 1" in the app
And I should find "Test scorm name" in the app And I should find "Test scorm name" in the app
And I should find "Test feedback name" in the app
And I should find "Test lesson name" in the app
And I should find "Test workshop name" in the app And I should find "Test workshop name" in the app
And I should not find "Web links" in the app
And I should not find "Test glossary" in the app
Scenario: View blocks on drawer Scenario: View blocks on drawer
Given the following "blocks" exist: Given the following "blocks" exist:
@ -447,20 +455,20 @@ Feature: Test basic usage of one course in app
| activity_modules | Course | C1 | course-view-* | site-pre | | | activity_modules | Course | C1 | course-view-* | site-pre | |
And I entered the course "Course 1" as "student1" in the app And I entered the course "Course 1" as "student1" in the app
Then the header should be "Course 1" in the app Then the header should be "Course 1" in the app
And I should find "Test forum name" in the app
And I should find "Test wiki name" in the app
And I should find "Choice course 1" in the app And I should find "Choice course 1" in the app
And I should find "assignment" in the app And I should find "assignment" in the app
And I should find "Test forum name" in the app
And I should find "Test chat name" in the app
And I should find "Web links" in the app
And I should find "Test external name" in the app And I should find "Test external name" in the app
And I should find "Test feedback name" in the app
And I should find "Test glossary" in the app
And I should find "Quiz 1" in the app
And I should find "Test survey name" in the app And I should find "Test survey name" in the app
And I should find "Test wiki name" in the app And I should find "Test chat name" in the app
And I should find "Test lesson name" in the app And I should find "Quiz 1" in the app
And I should find "Test scorm name" in the app And I should find "Test scorm name" in the app
And I should find "Test feedback name" in the app
And I should find "Test lesson name" in the app
And I should find "Test workshop name" in the app And I should find "Test workshop name" in the app
And I should not find "Web links" in the app
And I should not find "Test glossary" in the app
Then I press "Open block drawer" in the app Then I press "Open block drawer" in the app
And I should find "HTML title test" in the app And I should find "HTML title test" in the app
And I should find "body test" in the app And I should find "body test" in the app

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 34 KiB

View File

@ -1898,12 +1898,14 @@ ion-popover {
&.md { &.md {
margin-top: 2px; margin-top: 2px;
margin-bottom: 2px; margin-bottom: 2px;
}
// Never show backdrop on popovers // Never show backdrop on popovers on Android
// @todo Apply box shadow on ios and make it transparent too. The main problem is the box arrow.
ion-backdrop { ion-backdrop {
background: transparent; background: transparent;
} }
} }
}
/* /*
* This is to solve popver issue in chrome 114 * This is to solve popver issue in chrome 114