2
0
Fork 0

Merge pull request #2671 from crazyserver/MOBILE-3660

Mobile 3660
main
Dani Palou 2021-02-08 08:14:07 +01:00 committed by GitHub
commit 3796654443
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 755 additions and 97 deletions

View File

@ -18,4 +18,4 @@ jobs:
- run: npx tslint -c ionic-migration.json -p tsconfig.json - run: npx tslint -c ionic-migration.json -p tsconfig.json
- run: npm run test:ci - run: npm run test:ci
- run: npm run build:prod - run: npm run build:prod
- run: result=$(find src -type f -iname '*.html' -exec grep -E 'class="[^"]+"[^>]+class="' {} \; | wc -l); test $result -eq 0 - run: result=$(find src -type f -iname '*.html' -exec sh -c 'cat {} | tr "\n" " " | grep -Eo "class=\"[^\"]+\"[^>]+class=\"" ' \; | wc -l); test $result -eq 0

View File

@ -13,7 +13,7 @@
// limitations under the License. // limitations under the License.
import { Component, OnInit, OnDestroy } from '@angular/core'; import { Component, OnInit, OnDestroy } from '@angular/core';
import { PopoverController, IonRefresher } from '@ionic/angular'; import { IonRefresher } from '@ionic/angular';
import { CoreApp } from '@services/app'; import { CoreApp } from '@services/app';
import { CoreEventObserver, CoreEvents } from '@singletons/events'; import { CoreEventObserver, CoreEvents } from '@singletons/events';
import { CoreLocalNotifications } from '@services/local-notifications'; import { CoreLocalNotifications } from '@services/local-notifications';
@ -35,7 +35,7 @@ import { CoreCategoryData, CoreCourses, CoreEnrolledCourseData } from '@features
import { CoreCoursesHelper } from '@features/courses/services/courses-helper'; import { CoreCoursesHelper } from '@features/courses/services/courses-helper';
import { AddonCalendarFilterPopoverComponent } from '../../components/filter/filter'; import { AddonCalendarFilterPopoverComponent } from '../../components/filter/filter';
import moment from 'moment'; import moment from 'moment';
import { Network, NgZone } from '@singletons'; import { Network, NgZone, PopoverController } from '@singletons';
import { CoreNavigator } from '@services/navigator'; import { CoreNavigator } from '@services/navigator';
import { Params } from '@angular/router'; import { Params } from '@angular/router';
import { Subscription } from 'rxjs'; import { Subscription } from 'rxjs';
@ -100,9 +100,7 @@ export class AddonCalendarDayPage implements OnInit, OnDestroy {
category: true, category: true,
}; };
constructor( constructor() {
private popoverCtrl: PopoverController,
) {
this.currentSiteId = CoreSites.instance.getCurrentSiteId(); this.currentSiteId = CoreSites.instance.getCurrentSiteId();
if (CoreLocalNotifications.instance.isAvailable()) { if (CoreLocalNotifications.instance.isAvailable()) {
@ -537,7 +535,7 @@ export class AddonCalendarDayPage implements OnInit, OnDestroy {
* @param event Event. * @param event Event.
*/ */
async openFilter(event: MouseEvent): Promise<void> { async openFilter(event: MouseEvent): Promise<void> {
const popover = await this.popoverCtrl.create({ const popover = await PopoverController.instance.create({
component: AddonCalendarFilterPopoverComponent, component: AddonCalendarFilterPopoverComponent,
componentProps: { componentProps: {
courses: this.courses, courses: this.courses,

View File

@ -13,7 +13,7 @@
// limitations under the License. // limitations under the License.
import { Component, OnInit, OnDestroy, ViewChild } from '@angular/core'; import { Component, OnInit, OnDestroy, ViewChild } from '@angular/core';
import { PopoverController, IonRefresher } from '@ionic/angular'; import { IonRefresher } from '@ionic/angular';
import { CoreApp } from '@services/app'; import { CoreApp } from '@services/app';
import { CoreEventObserver, CoreEvents } from '@singletons/events'; import { CoreEventObserver, CoreEvents } from '@singletons/events';
import { CoreSites } from '@services/sites'; import { CoreSites } from '@services/sites';
@ -23,7 +23,7 @@ import { AddonCalendar, AddonCalendarProvider, AddonCalendarUpdatedEventEvent }
import { AddonCalendarOffline } from '../../services/calendar-offline'; import { AddonCalendarOffline } from '../../services/calendar-offline';
import { AddonCalendarSync, AddonCalendarSyncEvents, AddonCalendarSyncProvider } from '../../services/calendar-sync'; import { AddonCalendarSync, AddonCalendarSyncEvents, AddonCalendarSyncProvider } from '../../services/calendar-sync';
import { AddonCalendarFilter, AddonCalendarHelper } from '../../services/calendar-helper'; import { AddonCalendarFilter, AddonCalendarHelper } from '../../services/calendar-helper';
import { Network, NgZone } from '@singletons'; import { Network, NgZone, PopoverController } from '@singletons';
import { Subscription } from 'rxjs'; import { Subscription } from 'rxjs';
import { CoreEnrolledCourseData } from '@features/courses/services/courses'; import { CoreEnrolledCourseData } from '@features/courses/services/courses';
import { ActivatedRoute, Params } from '@angular/router'; import { ActivatedRoute, Params } from '@angular/router';
@ -83,7 +83,6 @@ export class AddonCalendarIndexPage implements OnInit, OnDestroy {
}; };
constructor( constructor(
protected popoverCtrl: PopoverController,
protected route: ActivatedRoute, protected route: ActivatedRoute,
) { ) {
this.currentSiteId = CoreSites.instance.getCurrentSiteId(); this.currentSiteId = CoreSites.instance.getCurrentSiteId();
@ -341,7 +340,7 @@ export class AddonCalendarIndexPage implements OnInit, OnDestroy {
* @param event Event. * @param event Event.
*/ */
async openFilter(event: MouseEvent): Promise<void> { async openFilter(event: MouseEvent): Promise<void> {
const popover = await this.popoverCtrl.create({ const popover = await PopoverController.instance.create({
component: AddonCalendarFilterPopoverComponent, component: AddonCalendarFilterPopoverComponent,
componentProps: { componentProps: {
courses: this.courses, courses: this.courses,

View File

@ -13,7 +13,7 @@
// limitations under the License. // limitations under the License.
import { Component, ViewChild, OnDestroy, OnInit } from '@angular/core'; import { Component, ViewChild, OnDestroy, OnInit } from '@angular/core';
import { PopoverController, IonContent, IonRefresher } from '@ionic/angular'; import { IonContent, IonRefresher } from '@ionic/angular';
import { import {
AddonCalendarProvider, AddonCalendarProvider,
AddonCalendar, AddonCalendar,
@ -36,7 +36,7 @@ import { CoreConstants } from '@/core/constants';
import { AddonCalendarFilterPopoverComponent } from '../../components/filter/filter'; import { AddonCalendarFilterPopoverComponent } from '../../components/filter/filter';
import { Params } from '@angular/router'; import { Params } from '@angular/router';
import { Subscription } from 'rxjs'; import { Subscription } from 'rxjs';
import { Network, NgZone } from '@singletons'; import { Network, NgZone, PopoverController } from '@singletons';
import { CoreCoursesHelper } from '@features/courses/services/courses-helper'; import { CoreCoursesHelper } from '@features/courses/services/courses-helper';
import { CoreUtils } from '@services/utils/utils'; import { CoreUtils } from '@services/utils/utils';
import { CoreNavigator } from '@services/navigator'; import { CoreNavigator } from '@services/navigator';
@ -101,9 +101,7 @@ export class AddonCalendarListPage implements OnInit, OnDestroy {
category: true, category: true,
}; };
constructor( constructor() {
private popoverCtrl: PopoverController,
) {
this.siteHomeId = CoreSites.instance.getCurrentSiteHomeId(); this.siteHomeId = CoreSites.instance.getCurrentSiteHomeId();
this.notificationsEnabled = CoreLocalNotifications.instance.isAvailable(); this.notificationsEnabled = CoreLocalNotifications.instance.isAvailable();
@ -624,7 +622,7 @@ export class AddonCalendarListPage implements OnInit, OnDestroy {
* @param event Event. * @param event Event.
*/ */
async openFilter(event: MouseEvent): Promise<void> { async openFilter(event: MouseEvent): Promise<void> {
const popover = await this.popoverCtrl.create({ const popover = await PopoverController.instance.create({
component: AddonCalendarFilterPopoverComponent, component: AddonCalendarFilterPopoverComponent,
componentProps: { componentProps: {
courses: this.courses, courses: this.courses,

View File

@ -34,7 +34,6 @@ import { IonRefresher } from '@ionic/angular';
@Component({ @Component({
selector: 'page-addon-messages-settings', selector: 'page-addon-messages-settings',
templateUrl: 'settings.html', templateUrl: 'settings.html',
styleUrls: ['settings.scss'],
}) })
export class AddonMessagesSettingsPage implements OnInit, OnDestroy { export class AddonMessagesSettingsPage implements OnInit, OnDestroy {

View File

@ -1,10 +0,0 @@
:host {
.list-header {
margin-bottom: 0;
border-top: 0;
}
.toggle {
display: inline-block;
}
}

View File

@ -41,7 +41,7 @@ export class AddonNotificationsPushClickHandlerService implements CorePushNotifi
* @param notification The notification to check. * @param notification The notification to check.
* @return Whether the notification click is handled by this handler * @return Whether the notification click is handled by this handler
*/ */
async handles(notification: NotificationData): Promise<boolean> { async handles(notification: AddonNotificationsNotificationData): Promise<boolean> {
if (!notification.moodlecomponent) { if (!notification.moodlecomponent) {
// The notification doesn't come from Moodle. Handle it. // The notification doesn't come from Moodle. Handle it.
return true; return true;
@ -63,7 +63,7 @@ export class AddonNotificationsPushClickHandlerService implements CorePushNotifi
* @param notification Notification to mark. * @param notification Notification to mark.
* @return Promise resolved when done. * @return Promise resolved when done.
*/ */
protected async markAsRead(notification: NotificationData): Promise<void> { protected async markAsRead(notification: AddonNotificationsNotificationData): Promise<void> {
const notifId = notification.savedmessageid || notification.id; const notifId = notification.savedmessageid || notification.id;
if (!notifId) { if (!notifId) {
@ -81,7 +81,7 @@ export class AddonNotificationsPushClickHandlerService implements CorePushNotifi
* @param notification The notification to check. * @param notification The notification to check.
* @return Promise resolved when done. * @return Promise resolved when done.
*/ */
async handleClick(notification: NotificationData): Promise<void> { async handleClick(notification: AddonNotificationsNotificationData): Promise<void> {
if (notification.customdata?.extendedtext) { if (notification.customdata?.extendedtext) {
// Display the text in a modal. // Display the text in a modal.
@ -133,7 +133,7 @@ export class AddonNotificationsPushClickHandlerService implements CorePushNotifi
export class AddonNotificationsPushClickHandler extends makeSingleton(AddonNotificationsPushClickHandlerService) {} export class AddonNotificationsPushClickHandler extends makeSingleton(AddonNotificationsPushClickHandlerService) {}
type NotificationData = CorePushNotificationsNotificationBasicData & { type AddonNotificationsNotificationData = CorePushNotificationsNotificationBasicData & {
contexturl?: string; // URL related to the notification. contexturl?: string; // URL related to the notification.
savedmessageid?: number; // Notification ID (optional). savedmessageid?: number; // Notification ID (optional).
id?: number; // Notification ID (optional). id?: number; // Notification ID (optional).

View File

@ -13,7 +13,8 @@
// limitations under the License. // limitations under the License.
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { NavParams, PopoverController } from '@ionic/angular'; import { NavParams } from '@ionic/angular';
import { PopoverController } from '@singletons';
import { CoreContextMenuItemComponent } from './context-menu-item'; import { CoreContextMenuItemComponent } from './context-menu-item';
/** /**
@ -32,7 +33,6 @@ export class CoreContextMenuPopoverComponent {
constructor( constructor(
navParams: NavParams, navParams: NavParams,
protected popoverCtrl: PopoverController,
) { ) {
this.title = navParams.get('title'); this.title = navParams.get('title');
this.items = navParams.get('items') || []; this.items = navParams.get('items') || [];
@ -43,7 +43,7 @@ export class CoreContextMenuPopoverComponent {
* Close the popover. * Close the popover.
*/ */
closeMenu(item?: CoreContextMenuItemComponent): void { closeMenu(item?: CoreContextMenuItemComponent): void {
this.popoverCtrl.dismiss(item); PopoverController.instance.dismiss(item);
} }
/** /**

View File

@ -15,10 +15,9 @@
import { Component, Input, OnInit, OnDestroy, ElementRef } from '@angular/core'; import { Component, Input, OnInit, OnDestroy, ElementRef } from '@angular/core';
import { Subject } from 'rxjs'; import { Subject } from 'rxjs';
import { auditTime } from 'rxjs/operators'; import { auditTime } from 'rxjs/operators';
import { PopoverController } from '@ionic/angular';
import { CoreDomUtils } from '@services/utils/dom'; import { CoreDomUtils } from '@services/utils/dom';
import { CoreUtils } from '@services/utils/utils'; import { CoreUtils } from '@services/utils/utils';
import { Translate } from '@singletons'; import { PopoverController, Translate } from '@singletons';
import { CoreContextMenuItemComponent } from './context-menu-item'; import { CoreContextMenuItemComponent } from './context-menu-item';
import { CoreContextMenuPopoverComponent } from './context-menu-popover'; import { CoreContextMenuPopoverComponent } from './context-menu-popover';
@ -47,7 +46,6 @@ export class CoreContextMenuComponent implements OnInit, OnDestroy {
constructor( constructor(
protected popoverCtrl: PopoverController,
elementRef: ElementRef, elementRef: ElementRef,
) { ) {
// Create the stream and subscribe to it. We ignore successive changes during 250ms. // Create the stream and subscribe to it. We ignore successive changes during 250ms.
@ -179,7 +177,7 @@ export class CoreContextMenuComponent implements OnInit, OnDestroy {
*/ */
async showContextMenu(event: MouseEvent): Promise<void> { async showContextMenu(event: MouseEvent): Promise<void> {
if (!this.expanded) { if (!this.expanded) {
const popover = await this.popoverCtrl.create( const popover = await PopoverController.instance.create(
{ {
event, event,
component: CoreContextMenuPopoverComponent, component: CoreContextMenuPopoverComponent,

View File

@ -13,7 +13,6 @@
// limitations under the License. // limitations under the License.
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { NavController } from '@ionic/angular';
import { CoreSites } from '@services/sites'; import { CoreSites } from '@services/sites';
import { CoreDomUtils } from '@services/utils/dom'; import { CoreDomUtils } from '@services/utils/dom';
import { CoreContentLinksDelegate, CoreContentLinksAction } from './contentlinks-delegate'; import { CoreContentLinksDelegate, CoreContentLinksAction } from './contentlinks-delegate';
@ -83,6 +82,7 @@ export class CoreContentLinksHelperProvider {
* Goes to a certain page in a certain site. If the site is current site it will perform a regular navigation, * Goes to a certain page in a certain site. If the site is current site it will perform a regular navigation,
* otherwise it will 'redirect' to the other site. * otherwise it will 'redirect' to the other site.
* *
* @param navCtrlUnused Deprecated param.
* @param pageName Name of the page to go. * @param pageName Name of the page to go.
* @param pageParams Params to send to the page. * @param pageParams Params to send to the page.
* @param siteId Site ID. If not defined, current site. * @param siteId Site ID. If not defined, current site.
@ -90,7 +90,7 @@ export class CoreContentLinksHelperProvider {
* @return Promise resolved when done. * @return Promise resolved when done.
* @deprecated since 3.9.5. Use CoreNavigator.navigateToSitePath instead. * @deprecated since 3.9.5. Use CoreNavigator.navigateToSitePath instead.
*/ */
async goInSite(navCtrl: NavController, pageName: string, pageParams: Params, siteId?: string): Promise<void> { async goInSite(navCtrlUnused: unknown, pageName: string, pageParams: Params, siteId?: string): Promise<void> {
await CoreNavigator.instance.navigateToSitePath(pageName, { params: pageParams, siteId }); await CoreNavigator.instance.navigateToSitePath(pageName, { params: pageParams, siteId });
} }

View File

@ -223,7 +223,8 @@ export class CoreCourseModuleMainResourceComponent implements OnInit, OnDestroy,
* Go to blog posts. * Go to blog posts.
*/ */
async gotoBlog(): Promise<void> { async gotoBlog(): Promise<void> {
// @todo return this.linkHelper.goInSite(this.navCtrl, 'AddonBlogEntriesPage', { cmId: this.module.id }); // const params: Params = { cmId: this.module?.id };
// @todo return CoreNavigator.instance.navigateToSitePath('AddonBlogEntriesPage', { params });
} }
/** /**

View File

@ -162,7 +162,7 @@ export class CoreCourseProvider {
* @return Whether the current view is a certain course. * @return Whether the current view is a certain course.
*/ */
// eslint-disable-next-line @typescript-eslint/no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars
currentViewIsCourse(navCtrl: any, courseId: number): boolean { currentViewIsCourse(courseId: number): boolean {
// @todo implement // @todo implement
return false; return false;
} }

View File

@ -13,10 +13,10 @@
// limitations under the License. // limitations under the License.
import { Component, Input, OnInit } from '@angular/core'; import { Component, Input, OnInit } from '@angular/core';
import { PopoverController } from '@ionic/angular';
import { CoreCourses } from '../../services/courses'; import { CoreCourses } from '../../services/courses';
import { CoreEnrolledCourseDataWithExtraInfoAndOptions } from '../../services/courses-helper'; import { CoreEnrolledCourseDataWithExtraInfoAndOptions } from '../../services/courses-helper';
import { CorePrefetchStatusInfo } from '@features/course/services/course-helper'; import { CorePrefetchStatusInfo } from '@features/course/services/course-helper';
import { PopoverController } from '@singletons';
/** /**
* This component is meant to display a popover with the course options. * This component is meant to display a popover with the course options.
@ -32,10 +32,6 @@ export class CoreCoursesCourseOptionsMenuComponent implements OnInit {
downloadCourseEnabled = false; downloadCourseEnabled = false;
constructor(
protected popoverController: PopoverController,
) { }
/** /**
* Component being initialized. * Component being initialized.
*/ */
@ -49,7 +45,7 @@ export class CoreCoursesCourseOptionsMenuComponent implements OnInit {
* @param action Action name to take. * @param action Action name to take.
*/ */
action(action: string): void { action(action: string): void {
this.popoverController.dismiss(action); PopoverController.instance.dismiss(action);
} }
} }

View File

@ -13,7 +13,6 @@
// limitations under the License. // limitations under the License.
import { Component, Input, OnInit, OnDestroy } from '@angular/core'; import { Component, Input, OnInit, OnDestroy } from '@angular/core';
import { PopoverController } from '@ionic/angular';
import { CoreEventCourseStatusChanged, CoreEventObserver, CoreEvents } from '@singletons/events'; import { CoreEventCourseStatusChanged, CoreEventObserver, CoreEvents } from '@singletons/events';
import { CoreSites } from '@services/sites'; import { CoreSites } from '@services/sites';
import { CoreDomUtils } from '@services/utils/dom'; import { CoreDomUtils } from '@services/utils/dom';
@ -21,7 +20,7 @@ import { CoreDomUtils } from '@services/utils/dom';
import { CoreCourses } from '@features/courses/services/courses'; import { CoreCourses } from '@features/courses/services/courses';
import { CoreCourse, CoreCourseProvider } from '@features/course/services/course'; import { CoreCourse, CoreCourseProvider } from '@features/course/services/course';
import { CoreCourseHelper, CorePrefetchStatusInfo } from '@features/course/services/course-helper'; import { CoreCourseHelper, CorePrefetchStatusInfo } from '@features/course/services/course-helper';
import { Translate } from '@singletons'; import { PopoverController, Translate } from '@singletons';
import { CoreConstants } from '@/core/constants'; import { CoreConstants } from '@/core/constants';
import { CoreEnrolledCourseDataWithExtraInfoAndOptions } from '../../services/courses-helper'; import { CoreEnrolledCourseDataWithExtraInfoAndOptions } from '../../services/courses-helper';
import { CoreCoursesCourseOptionsMenuComponent } from '../course-options-menu/course-options-menu'; import { CoreCoursesCourseOptionsMenuComponent } from '../course-options-menu/course-options-menu';
@ -62,10 +61,6 @@ export class CoreCoursesCourseProgressComponent implements OnInit, OnDestroy {
protected courseStatusObserver?: CoreEventObserver; protected courseStatusObserver?: CoreEventObserver;
protected siteUpdatedObserver?: CoreEventObserver; protected siteUpdatedObserver?: CoreEventObserver;
constructor(
protected popoverCtrl: PopoverController,
) { }
/** /**
* Component being initialized. * Component being initialized.
*/ */
@ -204,7 +199,7 @@ export class CoreCoursesCourseProgressComponent implements OnInit, OnDestroy {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
const popover = await this.popoverCtrl.create({ const popover = await PopoverController.instance.create({
component: CoreCoursesCourseOptionsMenuComponent, component: CoreCoursesCourseOptionsMenuComponent,
componentProps: { componentProps: {
course: this.course, course: this.course,

View File

@ -14,12 +14,19 @@
import { APP_INITIALIZER, NgModule } from '@angular/core'; import { APP_INITIALIZER, NgModule } from '@angular/core';
import { Routes } from '@angular/router'; import { Routes } from '@angular/router';
import { CoreContentLinksDelegate } from '@features/contentlinks/services/contentlinks-delegate';
import { CoreMainMenuHomeRoutingModule } from '@features/mainmenu/pages/home/home-routing.module'; import { CoreMainMenuHomeRoutingModule } from '@features/mainmenu/pages/home/home-routing.module';
import { CoreMainMenuHomeDelegate } from '@features/mainmenu/services/home-delegate'; import { CoreMainMenuHomeDelegate } from '@features/mainmenu/services/home-delegate';
import { CorePushNotificationsDelegate } from '@features/pushnotifications/services/push-delegate';
import { CoreCoursesCourseLinkHandler } from './services/handlers/course-link';
import { CoreCoursesIndexLinkHandler } from './services/handlers/courses-index-link';
import { CoreDashboardHomeHandler, CoreDashboardHomeHandlerService } from './services/handlers/dashboard-home'; import { CoreDashboardHomeHandler, CoreDashboardHomeHandlerService } from './services/handlers/dashboard-home';
import { CoreCoursesDashboardLinkHandler } from './services/handlers/dashboard-link';
import { CoreCoursesEnrolPushClickHandler } from './services/handlers/enrol-push-click';
import { CoreCoursesMyCoursesHomeHandler, CoreCoursesMyCoursesHomeHandlerService } from './services/handlers/my-courses-home'; import { CoreCoursesMyCoursesHomeHandler, CoreCoursesMyCoursesHomeHandlerService } from './services/handlers/my-courses-home';
import { CoreCoursesRequestPushClickHandler } from './services/handlers/request-push-click';
const mainMenuHomeChildrenRoutes: Routes = [ const mainMenuHomeChildrenRoutes: Routes = [
{ {
@ -59,6 +66,11 @@ const mainMenuHomeSiblingRoutes: Routes = [
useFactory: () => () => { useFactory: () => () => {
CoreMainMenuHomeDelegate.instance.registerHandler(CoreDashboardHomeHandler.instance); CoreMainMenuHomeDelegate.instance.registerHandler(CoreDashboardHomeHandler.instance);
CoreMainMenuHomeDelegate.instance.registerHandler(CoreCoursesMyCoursesHomeHandler.instance); CoreMainMenuHomeDelegate.instance.registerHandler(CoreCoursesMyCoursesHomeHandler.instance);
CoreContentLinksDelegate.instance.registerHandler(CoreCoursesCourseLinkHandler.instance);
CoreContentLinksDelegate.instance.registerHandler(CoreCoursesIndexLinkHandler.instance);
CoreContentLinksDelegate.instance.registerHandler(CoreCoursesDashboardLinkHandler.instance);
CorePushNotificationsDelegate.instance.registerClickHandler(CoreCoursesEnrolPushClickHandler.instance);
CorePushNotificationsDelegate.instance.registerClickHandler(CoreCoursesRequestPushClickHandler.instance);
}, },
}, },
], ],

View File

@ -161,6 +161,7 @@ export class CoreCoursesDashboardPage implements OnInit, OnDestroy {
* Open page to manage courses storage. * Open page to manage courses storage.
*/ */
manageCoursesStorage(): void { manageCoursesStorage(): void {
// AddonStorageManagerCoursesStoragePage
// @todo this.navCtrl.navigateForward(['/main/home/courses/storage']); // @todo this.navCtrl.navigateForward(['/main/home/courses/storage']);
} }

View File

@ -13,14 +13,12 @@
// limitations under the License. // limitations under the License.
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
// import { PopoverController } from '@ionic/angular';
import { CoreUtils } from '@services/utils/utils'; import { CoreUtils } from '@services/utils/utils';
import { CoreSites } from '@services/sites'; import { CoreSites } from '@services/sites';
import { CoreCourses, CoreCourseSearchedData, CoreCourseUserAdminOrNavOptionIndexed, CoreEnrolledCourseData } from './courses'; import { CoreCourses, CoreCourseSearchedData, CoreCourseUserAdminOrNavOptionIndexed, CoreEnrolledCourseData } from './courses';
import { makeSingleton, Translate } from '@singletons'; import { makeSingleton, Translate } from '@singletons';
import { CoreWSExternalFile } from '@services/ws'; import { CoreWSExternalFile } from '@services/ws';
import { AddonCourseCompletion } from '@/addons/coursecompletion/services/coursecompletion'; import { AddonCourseCompletion } from '@/addons/coursecompletion/services/coursecompletion';
// import { CoreCoursePickerMenuPopoverComponent } from '@components/course-picker-menu/course-picker-menu-popover';
/** /**
* Helper to gather some common courses functions. * Helper to gather some common courses functions.
@ -276,19 +274,6 @@ export class CoreCoursesHelperProvider {
})); }));
} }
/**
* Show a context menu to select a course, and return the courseId and categoryId of the selected course (-1 for all courses).
* Returns an empty object if popover closed without picking a course.
*
* @param event Click event.
* @param courses List of courses, from CoreCoursesHelperProvider.getCoursesForPopover.
* @param courseId The course to select at start.
* @return Promise resolved with the course ID and category ID.
*/
async selectCourse(): Promise<void> {
// @todo params and logic
}
} }
export class CoreCoursesHelper extends makeSingleton(CoreCoursesHelperProvider) { } export class CoreCoursesHelper extends makeSingleton(CoreCoursesHelperProvider) { }

View File

@ -1168,8 +1168,6 @@ export class CoreCourses extends makeSingleton(CoreCoursesProvider) {}
/** /**
* Data sent to the EVENT_MY_COURSES_UPDATED. * Data sent to the EVENT_MY_COURSES_UPDATED.
*
* @todo course type.
*/ */
export type CoreCoursesMyCoursesUpdatedEventData = { export type CoreCoursesMyCoursesUpdatedEventData = {
action: string; // Action performed. action: string; // Action performed.

View File

@ -0,0 +1,342 @@
// (C) Copyright 2015 Moodle Pty Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import { Injectable } from '@angular/core';
import { CoreSites } from '@services/sites';
import { CoreDomUtils } from '@services/utils/dom';
import { CoreContentLinksHandlerBase } from '@features/contentlinks/classes/base-handler';
import { CoreCourse } from '@features/course/services/course';
import { CoreCourseHelper } from '@features/course/services/course-helper';
import { CoreCourseAnyCourseData, CoreCourses, CoreCoursesProvider, CoreEnrolledCourseData } from '../courses';
import { CoreLogger } from '@singletons/logger';
import { makeSingleton, Translate } from '@singletons';
import { CoreContentLinksAction } from '@features/contentlinks/services/contentlinks-delegate';
import { Params } from '@angular/router';
import { CoreError } from '@classes/errors/error';
import { CoreUtils } from '@services/utils/utils';
import { CoreTextUtils } from '@services/utils/text';
import { CoreIonLoadingElement } from '@classes/ion-loading';
/**
* Handler to treat links to course view or enrol (except site home).
*/
@Injectable({ providedIn: 'root' })
export class CoreCoursesCourseLinkHandlerService extends CoreContentLinksHandlerBase {
name = 'CoreCoursesCourseLinkHandler';
pattern = /((\/enrol\/index\.php)|(\/course\/enrol\.php)|(\/course\/view\.php)).*([?&]id=\d+)/;
protected waitStart = 0;
protected logger: CoreLogger;
constructor() {
super();
this.logger = CoreLogger.getInstance('CoreCoursesCourseLinkHandler');
}
/**
* Get the list of actions for a link (url).
*
* @param siteIds List of sites the URL belongs to.
* @param url The URL to treat.
* @param params The params of the URL. E.g. 'mysite.com?id=1' -> {id: 1}
* @param courseId Course ID related to the URL. Optional but recommended.
* @return List of (or promise resolved with list of) actions.
*/
getActions(
siteIds: string[],
url: string,
params: Params,
): CoreContentLinksAction[] | Promise<CoreContentLinksAction[]> {
const courseId = parseInt(params.id, 10);
const sectionId = params.sectionid ? parseInt(params.sectionid, 10) : null;
const pageParams: Params = {
sectionId: sectionId || null,
};
let sectionNumber = typeof params.section != 'undefined' ? parseInt(params.section, 10) : NaN;
if (!sectionId && !sectionNumber) {
// Check if the URL has a hash to navigate to the section.
const matches = url.match(/#section-(\d+)/);
if (matches && matches[1]) {
sectionNumber = parseInt(matches[1], 10);
}
}
if (!isNaN(sectionNumber)) {
pageParams.sectionNumber = sectionNumber;
}
return [{
action: (siteId): void => {
siteId = siteId || CoreSites.instance.getCurrentSiteId();
if (siteId == CoreSites.instance.getCurrentSiteId()) {
// Check if we already are in the course index page.
if (CoreCourse.instance.currentViewIsCourse(courseId)) {
// Current view is this course, just select the contents tab.
CoreCourse.instance.selectCourseTab('', pageParams);
return;
} else {
this.actionEnrol(courseId, url, pageParams).catch(() => {
// Ignore errors.
});
}
} else {
// Make the course the new history root (to avoid "loops" in history).
CoreCourseHelper.instance.getAndOpenCourse(courseId, pageParams, siteId);
}
},
}];
}
/**
* Check if the handler is enabled for a certain site (site + user) and a URL.
* If not defined, defaults to true.
*
* @param siteId The site ID.
* @param url The URL to treat.
* @param params The params of the URL. E.g. 'mysite.com?id=1' -> {id: 1}
* @param courseId Course ID related to the URL. Optional but recommended.
* @return Whether the handler is enabled for the URL and site.
*/
async isEnabled(siteId: string, url: string, params: Params, courseId?: number): Promise<boolean> {
courseId = parseInt(params.id, 10);
if (!courseId) {
return false;
}
// Get the course id of Site Home.
return CoreSites.instance.getSiteHomeId(siteId).then((siteHomeId) => courseId != siteHomeId);
}
/**
* Action to perform when an enrol link is clicked.
*
* @param courseId Course ID.
* @param url Treated URL.
* @param pageParams Params to send to the new page.
* @return Promise resolved when done.
*/
protected async actionEnrol(courseId: number, url: string, pageParams: Params): Promise<void> {
const modal = await CoreDomUtils.instance.showModalLoading();
let course: CoreCourseAnyCourseData | { id: number } | undefined;
// Check if user is enrolled in the course.
try {
course = await CoreCourses.instance.getUserCourse(courseId);
} catch {
course = await this.checkSelfUserCanSelfEnrolOrAccess(courseId, url, modal);
}
// Check if we need to retrieve the course.
if (!course) {
try {
const data = await CoreCourseHelper.instance.getCourse(courseId);
course = data.course;
} catch {
// Cannot get course, return a "fake".
course = { id: courseId };
}
}
modal.dismiss();
// Now open the course.
CoreCourseHelper.instance.openCourse(course, pageParams);
}
/**
* Check if the user can self enrol or access the course.
*
* @param courseId Course ID.
* @param url Treated URL.
* @param modal Modal, to dismiss when needed.
* @return The course after self enrolling or undefined if the user has access but is not enrolled.
*/
protected checkSelfUserCanSelfEnrolOrAccess(
courseId: number,
url: string,
modal: CoreIonLoadingElement,
): Promise<CoreEnrolledCourseData | undefined> {
// User is not enrolled in the course. Check if can self enrol.
return this.canSelfEnrol(courseId).then(async () => {
modal.dismiss();
const isEnrolUrl = !!url.match(/(\/enrol\/index\.php)|(\/course\/enrol\.php)/);
// The user can self enrol. If it's not a enrolment URL we'll ask for confirmation.
if (!isEnrolUrl) {
try {
await CoreDomUtils.instance.showConfirm(Translate.instance.instant('core.courses.confirmselfenrol'));
} catch {
// User cancelled. Check if the user can view the course contents (guest access or similar).
await CoreCourse.instance.getSections(courseId, false, true);
return;
}
}
// Enrol URL or user confirmed.
try {
return this.selfEnrol(courseId);
} catch (error) {
if (error) {
CoreDomUtils.instance.showErrorModal(error);
}
throw error;
}
}, async (error) => {
// Can't self enrol. Check if the user can view the course contents (guest access or similar).
try {
await CoreCourse.instance.getSections(courseId, false, true);
} catch {
// Error. Show error message and allow the user to open the link in browser.
modal.dismiss();
if (error) {
error = CoreTextUtils.instance.getErrorMessageFromError(error) || error;
}
if (!error) {
error = Translate.instance.instant('core.courses.notenroled');
}
const body = CoreTextUtils.instance.buildSeveralParagraphsMessage(
[error, Translate.instance.instant('core.confirmopeninbrowser')],
);
try {
await CoreDomUtils.instance.showConfirm(body);
CoreSites.instance.getCurrentSite()?.openInBrowserWithAutoLogin(url);
} catch {
// User cancelled.
};
throw error;
}
return undefined;
});
}
/**
* Check if a user can be "automatically" self enrolled in a course.
*
* @param courseId Course ID.
* @return Promise resolved if user can be enrolled in a course, rejected otherwise.
*/
protected async canSelfEnrol(courseId: number): Promise<void> {
// Check that the course has self enrolment enabled.
const methods = await CoreCourses.instance.getCourseEnrolmentMethods(courseId);
let isSelfEnrolEnabled = false;
let instances = 0;
methods.forEach((method) => {
if (method.type == 'self' && method.status) {
isSelfEnrolEnabled = true;
instances++;
}
});
if (!isSelfEnrolEnabled || instances != 1) {
// Self enrol not enabled or more than one instance.
throw new CoreError('Self enrol not enabled in course');
}
}
/**
* Try to self enrol a user in a course.
*
* @param courseId Course ID.
* @param password Password.
* @return Promise resolved when the user is enrolled, rejected otherwise.
*/
protected async selfEnrol(courseId: number, password?: string): Promise<CoreEnrolledCourseData | undefined> {
const modal = await CoreDomUtils.instance.showModalLoading();
try {
await CoreCourses.instance.selfEnrol(courseId, password);
// Success self enrolling the user, invalidate the courses list.
await CoreUtils.instance.ignoreErrors(CoreCourses.instance.invalidateUserCourses());
try {
// Sometimes the list of enrolled courses takes a while to be updated. Wait for it.
return this.waitForEnrolled(courseId, true);
} finally {
modal.dismiss();
}
} catch (error) {
modal.dismiss();
if (error && error.code === CoreCoursesProvider.ENROL_INVALID_KEY) {
// Invalid password. Allow the user to input password.
const title = Translate.instance.instant('core.courses.selfenrolment');
const body = ' '; // Empty message.
const placeholder = Translate.instance.instant('core.courses.password');
if (typeof password != 'undefined') {
// The user attempted a password. Show an error message.
CoreDomUtils.instance.showErrorModal(error);
}
password = await CoreDomUtils.instance.showPrompt(body, title, placeholder);
return this.selfEnrol(courseId, password);
} else {
throw error;
}
}
}
/**
* Wait for the user to be enrolled in a course.
*
* @param courseId The course ID.
* @param first If it's the first call (true) or it's a recursive call (false).
* @return Promise resolved when enrolled or timeout.
*/
protected async waitForEnrolled(courseId: number, first?: boolean): Promise<CoreEnrolledCourseData | undefined> {
if (first) {
this.waitStart = Date.now();
}
// Check if user is enrolled in the course.
await CoreUtils.instance.ignoreErrors(CoreCourses.instance.invalidateUserCourses());
try {
return CoreCourses.instance.getUserCourse(courseId);
} catch {
// Not enrolled, wait a bit and try again.
if (Date.now() - this.waitStart > 60000) {
// Max time reached, stop.
return;
}
return new Promise((resolve, reject): void => {
setTimeout(() => {
this.waitForEnrolled(courseId)
.then(resolve).catch(reject);
}, 5000);
});
}
}
}
export class CoreCoursesCourseLinkHandler extends makeSingleton(CoreCoursesCourseLinkHandlerService) {}

View File

@ -0,0 +1,65 @@
// (C) Copyright 2015 Moodle Pty Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import { Injectable } from '@angular/core';
import { Params } from '@angular/router';
import { CoreContentLinksHandlerBase } from '@features/contentlinks/classes/base-handler';
import { CoreContentLinksAction } from '@features/contentlinks/services/contentlinks-delegate';
import { CoreNavigator } from '@services/navigator';
import { makeSingleton } from '@singletons';
import { CoreCourses } from '../courses';
import { CoreCoursesMyCoursesHomeHandlerService } from './my-courses-home';
/**
* Handler to treat links to course index (list of courses).
*/
@Injectable({ providedIn: 'root' })
export class CoreCoursesIndexLinkHandlerService extends CoreContentLinksHandlerBase {
name = 'CoreCoursesIndexLinkHandler';
featureName = 'CoreMainMenuDelegate_CoreCourses';
pattern = /\/course\/?(index\.php.*)?$/;
/**
* Get the list of actions for a link (url).
*
* @param siteIds List of sites the URL belongs to.
* @param url The URL to treat.
* @param params The params of the URL. E.g. 'mysite.com?id=1' -> {id: 1}
* @return List of (or promise resolved with list of) actions.
*/
getActions(siteIds: string[], url: string, params: Params): CoreContentLinksAction[] {
return [{
action: (siteId): void => {
let pageName = CoreCoursesMyCoursesHomeHandlerService.PAGE_NAME;
if (CoreCourses.instance.isGetCoursesByFieldAvailable()) {
if (params.categoryid) {
pageName += '/categories/' + params.categoryid;
} else {
pageName += '/all';
}
} else {
// By default, go to My Courses.
pageName += '/my';
}
CoreNavigator.instance.navigateToSitePath(pageName, { siteId });
},
}];
}
}
export class CoreCoursesIndexLinkHandler extends makeSingleton(CoreCoursesIndexLinkHandlerService) {}

View File

@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
import { AddonBlockTimeline } from '@addons/block/timeline/services/timeline';
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { CoreBlockDelegate } from '@features/block/services/block-delegate'; import { CoreBlockDelegate } from '@features/block/services/block-delegate';
import { CoreMainMenuHomeHandler, CoreMainMenuHomeHandlerToDisplay } from '@features/mainmenu/services/home-delegate'; import { CoreMainMenuHomeHandler, CoreMainMenuHomeHandlerToDisplay } from '@features/mainmenu/services/home-delegate';
@ -45,11 +46,37 @@ export class CoreDashboardHomeHandlerService implements CoreMainMenuHomeHandler
* @return Whether or not the handler is enabled on a site level. * @return Whether or not the handler is enabled on a site level.
*/ */
async isEnabledForSite(siteId?: string): Promise<boolean> { async isEnabledForSite(siteId?: string): Promise<boolean> {
const promises: Promise<void>[] = [];
let blocksEnabled = false;
let dashboardAvailable = false;
// Check if blocks and 3.6 dashboard is enabled.
promises.push(CoreBlockDelegate.instance.areBlocksDisabled(siteId).then((disabled) => {
blocksEnabled = !disabled;
return;
}));
promises.push(CoreCoursesDashboard.instance.isAvailable().then((available) => {
dashboardAvailable = available;
return;
}));
await Promise.all(promises);
if (dashboardAvailable && blocksEnabled) {
const blocks = await CoreCoursesDashboard.instance.getDashboardBlocks(undefined, siteId); const blocks = await CoreCoursesDashboard.instance.getDashboardBlocks(undefined, siteId);
return CoreBlockDelegate.instance.hasSupportedBlock(blocks); return CoreBlockDelegate.instance.hasSupportedBlock(blocks);
} }
// Check if my overview is enabled. If it's enabled we will fake enabled blocks.
const timelineEnabled = await AddonBlockTimeline.instance.isAvailable();
return timelineEnabled && blocksEnabled;
}
/** /**
* Returns the data needed to render the handler. * Returns the data needed to render the handler.
* *

View File

@ -0,0 +1,57 @@
// (C) Copyright 2015 Moodle Pty Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import { Injectable } from '@angular/core';
import { CoreContentLinksHandlerBase } from '@features/contentlinks/classes/base-handler';
import { CoreContentLinksAction } from '@features/contentlinks/services/contentlinks-delegate';
import { CoreNavigator } from '@services/navigator';
import { makeSingleton } from '@singletons';
import { CoreDashboardHomeHandler, CoreDashboardHomeHandlerService } from './dashboard-home';
/**
* Handler to treat links to my overview.
*/
@Injectable({ providedIn: 'root' })
export class CoreCoursesDashboardLinkHandlerService extends CoreContentLinksHandlerBase {
name = 'CoreCoursesMyOverviewLinkHandler';
pattern = /\/my\/?$/;
/**
* Get the list of actions for a link (url).
*
* @return List of (or promise resolved with list of) actions.
*/
getActions(): CoreContentLinksAction[] | Promise<CoreContentLinksAction[]> {
return [{
action: (siteId): void => {
// Use redirect to select the tab.
CoreNavigator.instance.navigateToSitePath(CoreDashboardHomeHandlerService.PAGE_NAME, { siteId });
},
}];
}
/**
* Check if the handler is enabled for a certain site (site + user) and a URL.
*
* @param siteId The site ID.
* @return Whether the handler is enabled for the URL and site.
*/
isEnabled(siteId: string): boolean | Promise<boolean> {
return CoreDashboardHomeHandler.instance.isEnabledForSite(siteId);
}
}
export class CoreCoursesDashboardLinkHandler extends makeSingleton(CoreCoursesDashboardLinkHandlerService) {}

View File

@ -0,0 +1,91 @@
// (C) Copyright 2015 Moodle Pty Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import { Injectable } from '@angular/core';
import { Params } from '@angular/router';
import { CoreCourseHelper } from '@features/course/services/course-helper';
import { CorePushNotificationsClickHandler } from '@features/pushnotifications/services/push-delegate';
import { CorePushNotificationsNotificationBasicData } from '@features/pushnotifications/services/pushnotifications';
import { CoreNavigator } from '@services/navigator';
import { CoreDomUtils } from '@services/utils/dom';
import { CoreUtils } from '@services/utils/utils';
import { makeSingleton } from '@singletons';
/**
* Handler for enrol push notifications clicks.
*/
@Injectable({ providedIn: 'root' })
export class CoreCoursesEnrolPushClickHandlerService implements CorePushNotificationsClickHandler {
name = 'CoreCoursesEnrolPushClickHandler';
priority = 200;
/**
* Check if a notification click is handled by this handler.
*
* @param notification The notification to check.
* @return Whether the notification click is handled by this handler
*/
async handles(notification: CorePushNotificationsNotificationBasicData): Promise<boolean> {
return CoreUtils.instance.isTrueOrOne(notification.notif) && notification.moodlecomponent?.indexOf('enrol_') === 0 &&
notification.name == 'expiry_notification';
}
/**
* Handle the notification click.
*
* @param notification The notification to check.
* @return Promise resolved when done.
*/
async handleClick(notification: CoreCoursesEnrolNotificationData): Promise<void> {
const courseId = notification.courseid;
const modal = await CoreDomUtils.instance.showModalLoading();
try {
const result = await CoreCourseHelper.instance.getCourse(courseId, notification.site);
const params: Params = {
course: result.course,
};
let page: string;
if (notification.contexturl?.indexOf('user/index.php') != -1) {
// Open the participants tab.
page = 'course';
params.selectedTab = 'user_participants'; // @todo: Set this when participants is done.
} else if (result.enrolled) {
// User is still enrolled, open the course.
page = 'course';
} else {
// User not enrolled anymore, open the preview page.
page = 'courses/preview';;
}
await CoreNavigator.instance.navigateToSitePath(page, { params, siteId: notification.site });
} catch (error) {
CoreDomUtils.instance.showErrorModalDefault(error, 'Error getting course.');
} finally {
modal.dismiss();
}
}
}
export class CoreCoursesEnrolPushClickHandler extends makeSingleton(CoreCoursesEnrolPushClickHandlerService) {}
type CoreCoursesEnrolNotificationData = CorePushNotificationsNotificationBasicData & {
courseid: number; // Course ID related to the notification.
contexturl?: string; // Context URL related to the notification.
};

View File

@ -17,6 +17,7 @@ import { CoreBlockDelegate } from '@features/block/services/block-delegate';
import { CoreMainMenuHomeHandler, CoreMainMenuHomeHandlerToDisplay } from '@features/mainmenu/services/home-delegate'; import { CoreMainMenuHomeHandler, CoreMainMenuHomeHandlerToDisplay } from '@features/mainmenu/services/home-delegate';
import { CoreSiteHome } from '@features/sitehome/services/sitehome'; import { CoreSiteHome } from '@features/sitehome/services/sitehome';
import { makeSingleton } from '@singletons'; import { makeSingleton } from '@singletons';
import { CoreCourses } from '../courses';
import { CoreCoursesDashboard } from '../dashboard'; import { CoreCoursesDashboard } from '../dashboard';
/** /**
@ -46,6 +47,12 @@ export class CoreCoursesMyCoursesHomeHandlerService implements CoreMainMenuHomeH
* @return Whether or not the handler is enabled on a site level. * @return Whether or not the handler is enabled on a site level.
*/ */
async isEnabledForSite(siteId?: string): Promise<boolean> { async isEnabledForSite(siteId?: string): Promise<boolean> {
const disabled = await CoreCourses.instance.isMyCoursesDisabled(siteId);
if (disabled) {
return false;
}
const blocks = await CoreCoursesDashboard.instance.getDashboardBlocks(undefined, siteId); const blocks = await CoreCoursesDashboard.instance.getDashboardBlocks(undefined, siteId);
return !CoreBlockDelegate.instance.hasSupportedBlock(blocks)&& !CoreSiteHome.instance.isAvailable(siteId); return !CoreBlockDelegate.instance.hasSupportedBlock(blocks)&& !CoreSiteHome.instance.isAvailable(siteId);

View File

@ -0,0 +1,103 @@
// (C) Copyright 2015 Moodle Pty Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import { Injectable } from '@angular/core';
import { Params } from '@angular/router';
import { CoreCourseHelper } from '@features/course/services/course-helper';
import { CorePushNotificationsClickHandler } from '@features/pushnotifications/services/push-delegate';
import { CorePushNotificationsNotificationBasicData } from '@features/pushnotifications/services/pushnotifications';
import { CoreNavigator } from '@services/navigator';
import { CoreSites } from '@services/sites';
import { CoreDomUtils } from '@services/utils/dom';
import { CoreTextUtils } from '@services/utils/text';
import { CoreUtils } from '@services/utils/utils';
import { makeSingleton } from '@singletons';
import { CoreCourses } from '../courses';
/**
* Handler for course request push notifications clicks.
*/
@Injectable({ providedIn: 'root' })
export class CoreCoursesRequestPushClickHandlerService implements CorePushNotificationsClickHandler {
name = 'CoreCoursesRequestPushClickHandler';
priority = 200;
/**
* Check if a notification click is handled by this handler.
*
* @param notification The notification to check.
* @return Whether the notification click is handled by this handler
*/
async handles(notification: CorePushNotificationsNotificationBasicData): Promise<boolean> {
// Don't support 'courserequestrejected', that way the app will open the notifications page.
return CoreUtils.instance.isTrueOrOne(notification.notif) && notification.moodlecomponent == 'moodle' &&
(notification.name == 'courserequested' || notification.name == 'courserequestapproved');
}
/**
* Handle the notification click.
*
* @param notification The notification to check.
* @return Promise resolved when done.
*/
async handleClick(notification: CoreCoursesRequestNotificationData): Promise<void> {
const courseId = notification.courseid;
if (notification.name == 'courserequested') {
// Feature not supported in the app, open in browser.
const site = await CoreSites.instance.getSite(notification.site);
const url = CoreTextUtils.instance.concatenatePaths(site.getURL(), 'course/pending.php');
await site.openInBrowserWithAutoLogin(url);
return;
}
// Open the course.
const modal = await CoreDomUtils.instance.showModalLoading();
await CoreUtils.instance.ignoreErrors(CoreCourses.instance.invalidateUserCourses(notification.site));
try {
const result = await CoreCourseHelper.instance.getCourse(courseId, notification.site);
const params: Params = {
course: result.course,
};
let page: string;
if (result.enrolled) {
// User is still enrolled, open the course.
page = 'course';
} else {
// User not enrolled (shouldn't happen), open the preview page.
page = 'courses/preview';
}
await CoreNavigator.instance.navigateToSitePath(page, { params, siteId: notification.site });
} catch (error) {
CoreDomUtils.instance.showErrorModalDefault(error, 'Error getting course.');
} finally {
modal.dismiss();
}
}
}
export class CoreCoursesRequestPushClickHandler extends makeSingleton(CoreCoursesRequestPushClickHandlerService) {}
type CoreCoursesRequestNotificationData = CorePushNotificationsNotificationBasicData & {
courseid: number; // Course ID related to the notification.
};

View File

@ -13,7 +13,6 @@
// limitations under the License. // limitations under the License.
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { NavController } from '@ionic/angular';
import { CoreLogger } from '@singletons/logger'; import { CoreLogger } from '@singletons/logger';
import { CoreSites, CoreSitesReadingStrategy } from '@services/sites'; import { CoreSites, CoreSitesReadingStrategy } from '@services/sites';
@ -440,7 +439,6 @@ export class CoreGradesHelperProvider {
* @param courseId Course ID to view. * @param courseId Course ID to view.
* @param userId User to view. If not defined, current user. * @param userId User to view. If not defined, current user.
* @param moduleId Module to view. If not defined, view all course grades. * @param moduleId Module to view. If not defined, view all course grades.
* @param navCtrl NavController to use.
* @param siteId Site ID. If not defined, current site. * @param siteId Site ID. If not defined, current site.
* @return Promise resolved when done. * @return Promise resolved when done.
*/ */
@ -448,11 +446,10 @@ export class CoreGradesHelperProvider {
courseId: number, courseId: number,
userId?: number, userId?: number,
moduleId?: number, moduleId?: number,
navCtrl?: NavController,
siteId?: string, siteId?: string,
): Promise<void> { ): Promise<void> {
const modal = await CoreDomUtils.instance.showModalLoading(); const modal = await CoreDomUtils.instance.showModalLoading();
let currentUserId; let currentUserId: number;
try { try {
const site = await CoreSites.instance.getSite(siteId); const site = await CoreSites.instance.getSite(siteId);
@ -504,7 +501,7 @@ export class CoreGradesHelperProvider {
} }
// View own grades. Check if we already are in the course index page. // View own grades. Check if we already are in the course index page.
if (CoreCourse.instance.currentViewIsCourse(navCtrl, courseId)) { if (CoreCourse.instance.currentViewIsCourse(courseId)) {
// Current view is this course, just select the grades tab. // Current view is this course, just select the grades tab.
CoreCourse.instance.selectCourseTab('CoreGrades'); CoreCourse.instance.selectCourseTab('CoreGrades');

View File

@ -50,11 +50,11 @@ export class CoreGradesUserLinkHandlerService extends CoreContentLinksHandlerBas
data = data || {}; data = data || {};
return [{ return [{
action: (siteId, navCtrl?): void => { action: (siteId): void => {
const userId = params.userid && parseInt(params.userid, 10); const userId = params.userid && parseInt(params.userid, 10);
const moduleId = data?.cmid && parseInt(data.cmid, 10) || undefined; const moduleId = data?.cmid && parseInt(data.cmid, 10) || undefined;
CoreGradesHelper.instance.goToGrades(courseId!, userId, moduleId, navCtrl, siteId); CoreGradesHelper.instance.goToGrades(courseId!, userId, moduleId, siteId);
}, },
}]; }];
} }

View File

@ -14,7 +14,6 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { Params } from '@angular/router'; import { Params } from '@angular/router';
import { NavController } from '@ionic/angular';
import { Md5 } from 'ts-md5/dist/md5'; import { Md5 } from 'ts-md5/dist/md5';
import { CoreApp, CoreStoreConfig } from '@services/app'; import { CoreApp, CoreStoreConfig } from '@services/app';
@ -447,7 +446,7 @@ export class CoreLoginHelperProvider {
/** /**
* Go to the initial page of a site depending on 'userhomepage' setting. * Go to the initial page of a site depending on 'userhomepage' setting.
* *
* @param navCtrl NavController to use. Defaults to app root NavController. * @param navCtrlUnused Deprecated param.
* @param page Name of the page to load after loading the main page. * @param page Name of the page to load after loading the main page.
* @param params Params to pass to the page. * @param params Params to pass to the page.
* @param options Navigation options. * @param options Navigation options.
@ -456,7 +455,7 @@ export class CoreLoginHelperProvider {
* @deprecated since 3.9.5. Use CoreNavigator.navigateToSiteHome or CoreNavigator.navigateToSitePath instead. * @deprecated since 3.9.5. Use CoreNavigator.navigateToSiteHome or CoreNavigator.navigateToSitePath instead.
*/ */
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
async goToSiteInitialPage(navCtrl?: NavController, page?: string, params?: any, options?: any, url?: string): Promise<void> { async goToSiteInitialPage(navCtrlUnused?: unknown, page?: string, params?: any, options?: any, url?: string): Promise<void> {
await CoreNavigator.instance.navigateToSiteHome({ await CoreNavigator.instance.navigateToSiteHome({
...options, ...options,
params: { params: {

View File

@ -14,6 +14,7 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { makeSingleton } from '@singletons'; import { makeSingleton } from '@singletons';
import { CoreMainMenuHomeDelegate } from '../home-delegate';
import { CoreMainMenuHandler, CoreMainMenuHandlerData } from '../mainmenu-delegate'; import { CoreMainMenuHandler, CoreMainMenuHandlerData } from '../mainmenu-delegate';
/** /**
@ -24,7 +25,7 @@ export class CoreMainMenuHomeHandlerService implements CoreMainMenuHandler {
static readonly PAGE_NAME = 'home'; static readonly PAGE_NAME = 'home';
name = 'CoreMainMenuHome'; name = 'CoreHome';
priority = 1100; priority = 1100;
/** /**
@ -39,13 +40,10 @@ export class CoreMainMenuHomeHandlerService implements CoreMainMenuHandler {
/** /**
* Check if the handler is enabled on a certain site. * Check if the handler is enabled on a certain site.
* *
* @param siteId Site ID. If not defined, current site.
* @return Whether or not the handler is enabled on a site level. * @return Whether or not the handler is enabled on a site level.
*/ */
// eslint-disable-next-line @typescript-eslint/no-unused-vars async isEnabledForSite(): Promise<boolean> {
async isEnabledForSite(siteId?: string): Promise<boolean> { return CoreMainMenuHomeDelegate.instance.getHandlers().length > 0;
// @todo
return true;
} }
/** /**
@ -55,7 +53,7 @@ export class CoreMainMenuHomeHandlerService implements CoreMainMenuHandler {
*/ */
getDisplayData(): CoreMainMenuHandlerData { getDisplayData(): CoreMainMenuHandlerData {
return { return {
icon: 'fa-home', icon: 'fas-home',
title: 'core.mainmenu.home', title: 'core.mainmenu.home',
page: CoreMainMenuHomeHandlerService.PAGE_NAME, page: CoreMainMenuHomeHandlerService.PAGE_NAME,
// @todo: subPage? The page can change due to core-tabs. // @todo: subPage? The page can change due to core-tabs.

View File

@ -25,6 +25,7 @@ import {
GestureController as GestureControllerService, GestureController as GestureControllerService,
ActionSheetController as ActionSheetControllerService, ActionSheetController as ActionSheetControllerService,
NavController as NavControllerService, NavController as NavControllerService,
PopoverController as PopoverControllerService,
} from '@ionic/angular'; } from '@ionic/angular';
import { Badge as BadgeService } from '@ionic-native/badge/ngx'; import { Badge as BadgeService } from '@ionic-native/badge/ngx';
@ -148,6 +149,7 @@ export class ActionSheetController extends makeSingleton(ActionSheetControllerSe
export class AlertController extends makeSingleton(AlertControllerService) {} export class AlertController extends makeSingleton(AlertControllerService) {}
export class LoadingController extends makeSingleton(LoadingControllerService) {} export class LoadingController extends makeSingleton(LoadingControllerService) {}
export class ModalController extends makeSingleton(ModalControllerService) {} export class ModalController extends makeSingleton(ModalControllerService) {}
export class PopoverController extends makeSingleton(PopoverControllerService) {}
export class ToastController extends makeSingleton(ToastControllerService) {} export class ToastController extends makeSingleton(ToastControllerService) {}
export class GestureController extends makeSingleton(GestureControllerService) {} export class GestureController extends makeSingleton(GestureControllerService) {}
export class ApplicationInit extends makeSingleton(ApplicationInitStatus) {} export class ApplicationInit extends makeSingleton(ApplicationInitStatus) {}

View File

@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
import { CoreContentLinksHelper } from '@features/contentlinks/services/contentlinks-helper';
import { NavController } from '@ionic/angular'; import { NavController } from '@ionic/angular';
import { CoreFileHelper } from '@services/file-helper'; import { CoreFileHelper } from '@services/file-helper';
@ -21,6 +22,8 @@ import { CoreUtils } from '@services/utils/utils';
/** /**
* Options for the open function. * Options for the open function.
*
* @deprecated since 3.9.5
*/ */
export type CoreWindowOpenOptions = { export type CoreWindowOpenOptions = {
/** /**
@ -46,10 +49,9 @@ export class CoreWindow {
* *
* @param url URL to open. * @param url URL to open.
* @param name Name of the browsing context into which to load the URL. * @param name Name of the browsing context into which to load the URL.
* @param options Other options.
* @return Promise resolved when done. * @return Promise resolved when done.
*/ */
static async open(url: string, name?: string, options?: CoreWindowOpenOptions): Promise<void> { static async open(url: string, name?: string): Promise<void> {
if (CoreUrlUtils.instance.isLocalFileUrl(url)) { if (CoreUrlUtils.instance.isLocalFileUrl(url)) {
const filename = url.substr(url.lastIndexOf('/') + 1); const filename = url.substr(url.lastIndexOf('/') + 1);
@ -64,13 +66,11 @@ export class CoreWindow {
await CoreUtils.instance.openFile(url); await CoreUtils.instance.openFile(url);
} else { } else {
let treated = false; let treated = false;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
options = options || {};
if (name != '_system') { if (name != '_system') {
// Check if it can be opened in the app. // Check if it can be opened in the app.
treated = false; treated = false;
// @todo await CoreContentLinksHelper.instance.handleLink(url, undefined, options.navCtrl, true, true); await CoreContentLinksHelper.instance.handleLink(url, undefined, true, true);
} }
if (!treated) { if (!treated) {