Merge pull request #1707 from dpalou/MOBILE-2795

Mobile 2795
main
Juan Leyva 2019-01-07 13:37:10 +01:00 committed by GitHub
commit 756fce9a84
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 97 additions and 14 deletions

View File

@ -133,6 +133,7 @@ export class AddonModLessonIndexComponent extends CoreCourseModuleMainActivityCo
this.accessInfo = info; this.accessInfo = info;
this.canManage = info.canmanage; this.canManage = info.canmanage;
this.canViewReports = info.canviewreports; this.canViewReports = info.canviewreports;
this.preventMessages = [];
if (this.lessonProvider.isLessonOffline(this.lesson)) { if (this.lessonProvider.isLessonOffline(this.lesson)) {
// Handle status. // Handle status.
@ -162,7 +163,8 @@ export class AddonModLessonIndexComponent extends CoreCourseModuleMainActivityCo
} }
if (info.preventaccessreasons && info.preventaccessreasons.length) { if (info.preventaccessreasons && info.preventaccessreasons.length) {
const askPassword = info.preventaccessreasons.length == 1 && this.lessonProvider.isPasswordProtected(info); let preventReason = this.lessonProvider.getPreventAccessReason(info, false);
const askPassword = preventReason.reason == 'passwordprotectedlesson';
if (askPassword) { if (askPassword) {
// The lesson requires a password. Check if there is one in memory or DB. // The lesson requires a password. Check if there is one in memory or DB.
@ -171,15 +173,21 @@ export class AddonModLessonIndexComponent extends CoreCourseModuleMainActivityCo
promises.push(promise.then((password) => { promises.push(promise.then((password) => {
return this.validatePassword(password); return this.validatePassword(password);
}).then(() => {
// Now that we have the password, get the access reason again ignoring the password.
preventReason = this.lessonProvider.getPreventAccessReason(info, true);
if (preventReason) {
this.preventMessages = [preventReason];
}
}).catch(() => { }).catch(() => {
// No password or the validation failed. Show password form. // No password or the validation failed. Show password form.
this.askPassword = true; this.askPassword = true;
this.preventMessages = info.preventaccessreasons; this.preventMessages = [preventReason];
lessonReady = false; lessonReady = false;
})); }));
} else { } else {
// Lesson cannot be started. // Lesson cannot be started.
this.preventMessages = info.preventaccessreasons; this.preventMessages = [preventReason];
lessonReady = false; lessonReady = false;
} }
} }
@ -293,7 +301,6 @@ export class AddonModLessonIndexComponent extends CoreCourseModuleMainActivityCo
*/ */
protected lessonReady(refresh?: boolean): void { protected lessonReady(refresh?: boolean): void {
this.askPassword = false; this.askPassword = false;
this.preventMessages = [];
this.leftDuringTimed = this.hasOffline || this.lessonProvider.leftDuringTimed(this.accessInfo); this.leftDuringTimed = this.hasOffline || this.lessonProvider.leftDuringTimed(this.accessInfo);
if (this.password) { if (this.password) {
@ -524,6 +531,12 @@ export class AddonModLessonIndexComponent extends CoreCourseModuleMainActivityCo
// Password validated. // Password validated.
this.lessonReady(false); this.lessonReady(false);
// Now that we have the password, get the access reason again ignoring the password.
const preventReason = this.lessonProvider.getPreventAccessReason(this.accessInfo, true);
if (preventReason) {
this.preventMessages = [preventReason];
}
// Log view now that we have the password. // Log view now that we have the password.
this.logView(); this.logView();
}).catch((error) => { }).catch((error) => {

View File

@ -245,9 +245,10 @@ export class AddonModLessonPlayerPage implements OnInit, OnDestroy {
if (info.preventaccessreasons && info.preventaccessreasons.length) { if (info.preventaccessreasons && info.preventaccessreasons.length) {
// If it's a password protected lesson and we have the password, allow playing it. // If it's a password protected lesson and we have the password, allow playing it.
if (!this.password || info.preventaccessreasons.length > 1 || !this.lessonProvider.isPasswordProtected(info)) { const preventReason = this.lessonProvider.getPreventAccessReason(info, !!this.password);
if (preventReason) {
// Lesson cannot be played, show message and go back. // Lesson cannot be played, show message and go back.
return Promise.reject(info.preventaccessreasons[0].message); return Promise.reject(preventReason.message);
} }
} }

View File

@ -2335,6 +2335,38 @@ export class AddonModLessonProvider {
return this.ROOT_CACHE_KEY + 'userRetake:' + lessonId; return this.ROOT_CACHE_KEY + 'userRetake:' + lessonId;
} }
/**
* Get the prevent access reason to display for a certain lesson.
*
* @param {any} info Lesson access info.
* @param {boolean} [ignorePassword] Whether password protected reason should be ignored (user already entered the password).
* @return {any} Prevent access reason.
*/
getPreventAccessReason(info: any, ignorePassword?: boolean): any {
let result;
if (info && info.preventaccessreasons) {
for (let i = 0; i < info.preventaccessreasons.length; i++) {
const entry = info.preventaccessreasons[i];
if (entry.reason == 'lessonopen' || entry.reason == 'lessonclosed') {
// Time restrictions are the most prioritary, return it.
return entry;
} else if (entry.reason == 'passwordprotectedlesson') {
if (!ignorePassword) {
// Treat password before all other reasons.
result = entry;
}
} else if (!result) {
// Rest of cases, just return any of them.
result = entry;
}
}
}
return result;
}
/** /**
* Check if a jump is correct. * Check if a jump is correct.
* Based in Moodle's jumpto_is_correct. * Based in Moodle's jumpto_is_correct.

View File

@ -1273,7 +1273,9 @@ export class CoreSite {
return this.domUtils.showAlert(this.translate.instant('core.notice'), alertMessage, undefined, 3000).then((alert) => { return this.domUtils.showAlert(this.translate.instant('core.notice'), alertMessage, undefined, 3000).then((alert) => {
return new Promise<InAppBrowserObject | void>((resolve, reject): void => { return new Promise<InAppBrowserObject | void>((resolve, reject): void => {
alert.onDidDismiss(() => { const subscription = alert.didDismiss.subscribe(() => {
subscription && subscription.unsubscribe();
if (inApp) { if (inApp) {
resolve(this.utils.openInApp(url, options)); resolve(this.utils.openInApp(url, options));
} else { } else {

View File

@ -697,7 +697,9 @@ export class CoreLoginHelperProvider {
*/ */
openChangePassword(siteUrl: string, error: string): void { openChangePassword(siteUrl: string, error: string): void {
this.domUtils.showAlert(this.translate.instant('core.notice'), error, undefined, 3000).then((alert) => { this.domUtils.showAlert(this.translate.instant('core.notice'), error, undefined, 3000).then((alert) => {
alert.onDidDismiss(() => { const subscription = alert.didDismiss.subscribe(() => {
subscription && subscription.unsubscribe();
this.utils.openInApp(siteUrl + '/login/change_password.php'); this.utils.openInApp(siteUrl + '/login/change_password.php');
}); });
}); });

View File

@ -12,7 +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 { Component, OnDestroy, ViewChild } from '@angular/core'; import { Component, OnDestroy, ViewChild, ChangeDetectorRef } from '@angular/core';
import { IonicPage, NavController, NavParams } from 'ionic-angular'; import { IonicPage, NavController, NavParams } from 'ionic-angular';
import { CoreSitesProvider } from '@providers/sites'; import { CoreSitesProvider } from '@providers/sites';
import { CoreEventsProvider } from '@providers/events'; import { CoreEventsProvider } from '@providers/events';
@ -42,7 +42,7 @@ export class CoreMainMenuPage implements OnDestroy {
@ViewChild('mainTabs') mainTabs: CoreIonTabsComponent; @ViewChild('mainTabs') mainTabs: CoreIonTabsComponent;
constructor(private menuDelegate: CoreMainMenuDelegate, private sitesProvider: CoreSitesProvider, navParams: NavParams, constructor(private menuDelegate: CoreMainMenuDelegate, private sitesProvider: CoreSitesProvider, navParams: NavParams,
private navCtrl: NavController, private eventsProvider: CoreEventsProvider) { private navCtrl: NavController, private eventsProvider: CoreEventsProvider, private cdr: ChangeDetectorRef) {
// Check if the menu was loaded with a redirect. // Check if the menu was loaded with a redirect.
const redirectPage = navParams.get('redirectPage'); const redirectPage = navParams.get('redirectPage');
@ -138,6 +138,9 @@ export class CoreMainMenuPage implements OnDestroy {
this.redirectParams = data.redirectParams; this.redirectParams = data.redirectParams;
} }
// Force change detection, otherwise sometimes the tab was selected before the params were applied.
this.cdr.detectChanges();
setTimeout(() => { setTimeout(() => {
// Let the tab load the params before navigating. // Let the tab load the params before navigating.
this.mainTabs.selectTabRootByIndex(i + 1); this.mainTabs.selectTabRootByIndex(i + 1);

View File

@ -25,6 +25,24 @@ import { CoreConfigProvider } from '../config';
import { CoreUrlUtilsProvider } from './url'; import { CoreUrlUtilsProvider } from './url';
import { CoreConstants } from '@core/constants'; import { CoreConstants } from '@core/constants';
import { Md5 } from 'ts-md5/dist/md5'; import { Md5 } from 'ts-md5/dist/md5';
import { Subject } from 'rxjs';
/**
* Interface that defines an extension of the Ionic Alert class, to support multiple listeners.
*/
export interface CoreAlert extends Alert {
/**
* Observable that will notify when the alert is dismissed.
* @type {Subject<{data: any, role: string}>}
*/
didDismiss: Subject<{data: any, role: string}>;
/**
* Observable that will notify when the alert will be dismissed.
* @type {Subject<{data: any, role: string}>}
*/
willDismiss: Subject<{data: any, role: string}>;
}
/* /*
* "Utils" service with helper functions for UI, DOM elements and HTML code. * "Utils" service with helper functions for UI, DOM elements and HTML code.
@ -886,9 +904,9 @@ export class CoreDomUtilsProvider {
* @param {string} message Message to show. * @param {string} message Message to show.
* @param {string} [buttonText] Text of the button. * @param {string} [buttonText] Text of the button.
* @param {number} [autocloseTime] Number of milliseconds to wait to close the modal. If not defined, modal won't be closed. * @param {number} [autocloseTime] Number of milliseconds to wait to close the modal. If not defined, modal won't be closed.
* @return {Promise<Alert>} Promise resolved with the alert modal. * @return {Promise<CoreAlert>} Promise resolved with the alert modal.
*/ */
showAlert(title: string, message: string, buttonText?: string, autocloseTime?: number): Promise<Alert> { showAlert(title: string, message: string, buttonText?: string, autocloseTime?: number): Promise<CoreAlert> {
const hasHTMLTags = this.textUtils.hasHTMLTags(message); const hasHTMLTags = this.textUtils.hasHTMLTags(message);
let promise; let promise;
@ -907,7 +925,7 @@ export class CoreDomUtilsProvider {
return this.displayedAlerts[alertId]; return this.displayedAlerts[alertId];
} }
const alert = this.alertCtrl.create({ const alert: CoreAlert = <any> this.alertCtrl.create({
title: title, title: title,
message: message, message: message,
buttons: [buttonText || this.translate.instant('core.ok')] buttons: [buttonText || this.translate.instant('core.ok')]
@ -924,8 +942,19 @@ export class CoreDomUtilsProvider {
// Store the alert and remove it when dismissed. // Store the alert and remove it when dismissed.
this.displayedAlerts[alertId] = alert; this.displayedAlerts[alertId] = alert;
alert.onDidDismiss(() => { // Define the observables to extend the Alert class. This will allow several callbacks instead of just one.
alert.didDismiss = new Subject();
alert.willDismiss = new Subject();
// Set the callbacks to trigger an observable event.
alert.onDidDismiss((data: any, role: string) => {
delete this.displayedAlerts[alertId]; delete this.displayedAlerts[alertId];
alert.didDismiss.next({data: data, role: role});
});
alert.onWillDismiss((data: any, role: string) => {
alert.willDismiss.next({data: data, role: role});
}); });
if (autocloseTime > 0) { if (autocloseTime > 0) {

View File

@ -8,6 +8,7 @@ information provided here is intended especially for developers.
- The value of the constant CoreCourseProvider.ALL_SECTIONS_ID has changed from -1 to -2. - The value of the constant CoreCourseProvider.ALL_SECTIONS_ID has changed from -1 to -2.
- Use of completionstatus on the module object has been deprecated, use completiondata instead. - Use of completionstatus on the module object has been deprecated, use completiondata instead.
- The function CoreSitesProvider.loadSite has changed, now it will trigger SESSION_EXPIRED event if the site is logged out. Its params and return value have changed. - The function CoreSitesProvider.loadSite has changed, now it will trigger SESSION_EXPIRED event if the site is logged out. Its params and return value have changed.
- When using CoreDomUtils.showAlert, please use alert.didDismiss.subscribe() instead of alert.onDidDismiss().
- The following strings have been deprecated: - The following strings have been deprecated:
core.dfdaymonthyear. Please use core.strftimedatefullshort instead. core.dfdaymonthyear. Please use core.strftimedatefullshort instead.
core.dfdayweekmonth. Please use core.strftimedayshort instead. core.dfdayweekmonth. Please use core.strftimedayshort instead.