From 59c4c2141b6d69c966455cb1062117628e994fcc Mon Sep 17 00:00:00 2001 From: Dani Palou Date: Mon, 3 Sep 2018 12:18:53 +0200 Subject: [PATCH 1/9] MOBILE-2567 notifications: Fix tslint warnings --- src/addon/notifications/pages/list/list.ts | 2 +- src/addon/notifications/providers/notifications.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/addon/notifications/pages/list/list.ts b/src/addon/notifications/pages/list/list.ts index e9634d095..9031abdc0 100644 --- a/src/addon/notifications/pages/list/list.ts +++ b/src/addon/notifications/pages/list/list.ts @@ -121,7 +121,7 @@ export class AddonNotificationsListPage { // Check if mark all notifications as read is enabled and there are some to read. if (this.notificationsProvider.isMarkAllNotificationsAsReadEnabled()) { promises.push(this.notificationsProvider.getUnreadNotificationsCount().then((unread) => { - this.canMarkAllNotificationsAsRead = unread > 0 + this.canMarkAllNotificationsAsRead = unread > 0; })); } else { this.canMarkAllNotificationsAsRead = false; diff --git a/src/addon/notifications/providers/notifications.ts b/src/addon/notifications/providers/notifications.ts index d7a1bde1b..bbd74caa4 100644 --- a/src/addon/notifications/providers/notifications.ts +++ b/src/addon/notifications/providers/notifications.ts @@ -244,10 +244,10 @@ export class AddonNotificationsProvider { const params = { useridto: this.sitesProvider.getCurrentSiteUserId() }; + return this.sitesProvider.getCurrentSite().write('core_message_mark_all_notifications_as_read', params); } - /** * Mark message notification as read. * From e327beaa3dcb20ebb25f2d4763c110bd39683fd2 Mon Sep 17 00:00:00 2001 From: Dani Palou Date: Mon, 3 Sep 2018 12:19:34 +0200 Subject: [PATCH 2/9] MOBILE-2567 build: Run gulp when compiling --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 007d42db8..b2c25cd47 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "ionic:build:before": "gulp", "ionic:watch:before": "gulp", "ionic:build:after": "gulp copy-component-templates", + "preionic:build": "gulp", "postionic:build": "gulp copy-component-templates", "desktop.pack": "electron-builder --dir", "desktop.dist": "electron-builder", From 9d09a31af501a9025ba76893af87783f52045514 Mon Sep 17 00:00:00 2001 From: Dani Palou Date: Mon, 3 Sep 2018 14:58:06 +0200 Subject: [PATCH 3/9] MOBILE-2567 assign: Fix leaving teacher view --- .../pages/submission-list/submission-list.ts | 17 ----------------- src/components/split-view/split-view.ts | 6 +++++- 2 files changed, 5 insertions(+), 18 deletions(-) diff --git a/src/addon/mod/assign/pages/submission-list/submission-list.ts b/src/addon/mod/assign/pages/submission-list/submission-list.ts index 3f661eb37..504a41b8d 100644 --- a/src/addon/mod/assign/pages/submission-list/submission-list.ts +++ b/src/addon/mod/assign/pages/submission-list/submission-list.ts @@ -92,23 +92,6 @@ export class AddonModAssignSubmissionListPage implements OnInit, OnDestroy { }); } - /** - * Check if we can leave the page or not. - * - * @return {boolean|Promise} Resolved if we can leave it, rejected if not. - */ - ionViewCanLeave(): boolean | Promise { - // If split view is enabled, check if we can leave the details page. - if (this.splitviewCtrl.isOn()) { - const detailsPage = this.splitviewCtrl.getDetailsNav().getActive().instance; - if (detailsPage && detailsPage.ionViewCanLeave) { - return detailsPage.ionViewCanLeave(); - } - } - - return true; - } - /** * Fetch assignment data. * diff --git a/src/components/split-view/split-view.ts b/src/components/split-view/split-view.ts index ec7dbd4a4..8808fa88e 100644 --- a/src/components/split-view/split-view.ts +++ b/src/components/split-view/split-view.ts @@ -109,6 +109,10 @@ export class CoreSplitViewComponent implements OnInit, OnDestroy { handleCanLeave(): void { // Listen for the didEnter event on the details nav to detect everytime a page is loaded. this.detailsDidEnterSubscription = this.detailNav.viewDidEnter.subscribe((detailsViewController: ViewController) => { + if (!this.isOn()) { + return; + } + const masterViewController = this.masterNav.getActive(); if (this.masterCanLeaveOverridden) { @@ -133,7 +137,7 @@ export class CoreSplitViewComponent implements OnInit, OnDestroy { return Promise.resolve().then(() => { if (this.originalMasterCanLeave) { // First call the master canLeave. - const result = this.originalMasterCanLeave(); + const result = this.originalMasterCanLeave.apply(masterViewController.instance); if (typeof result == 'boolean' && !result) { // User cannot leave, return a rejected promise so the details canLeave isn't executed. return Promise.reject(null); From a0d76b9370aab0d57b93cc4dbf70b95c9005d90a Mon Sep 17 00:00:00 2001 From: Dani Palou Date: Mon, 3 Sep 2018 16:42:29 +0200 Subject: [PATCH 4/9] MOBILE-2567 lti: Fix LTI icons not displayed --- src/addon/mod/lti/providers/module-handler.ts | 8 +++++--- src/core/course/providers/module-delegate.ts | 3 ++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/addon/mod/lti/providers/module-handler.ts b/src/addon/mod/lti/providers/module-handler.ts index c88705911..dfd0b38b4 100644 --- a/src/addon/mod/lti/providers/module-handler.ts +++ b/src/addon/mod/lti/providers/module-handler.ts @@ -14,6 +14,7 @@ import { Injectable } from '@angular/core'; import { NavController, NavOptions } from 'ionic-angular'; +import { DomSanitizer } from '@angular/platform-browser'; import { CoreCourseModuleHandler, CoreCourseModuleHandlerData } from '@core/course/providers/module-delegate'; import { CoreAppProvider } from '@providers/app'; import { CoreCourseProvider } from '@core/course/providers/course'; @@ -36,7 +37,8 @@ export class AddonModLtiModuleHandler implements CoreCourseModuleHandler { private domUtils: CoreDomUtilsProvider, private filepoolProvider: CoreFilepoolProvider, private sitesProvider: CoreSitesProvider, - private ltiProvider: AddonModLtiProvider) {} + private ltiProvider: AddonModLtiProvider, + private sanitizer: DomSanitizer) {} /** * Check if the handler is enabled on a site level. @@ -100,11 +102,11 @@ export class AddonModLtiModuleHandler implements CoreCourseModuleHandler { // Get the internal URL. return this.filepoolProvider.getSrcByUrl(siteId, icon, AddonModLtiProvider.COMPONENT, module.id); }).then((url) => { - data.icon = url; + data.icon = this.sanitizer.bypassSecurityTrustUrl(url); }).catch(() => { // Error downloading. If we're online we'll set the online url. if (this.appProvider.isOnline()) { - data.icon = icon; + data.icon = this.sanitizer.bypassSecurityTrustUrl(icon); } }); } diff --git a/src/core/course/providers/module-delegate.ts b/src/core/course/providers/module-delegate.ts index b367efbf1..459110be2 100644 --- a/src/core/course/providers/module-delegate.ts +++ b/src/core/course/providers/module-delegate.ts @@ -14,6 +14,7 @@ import { Injectable, Injector } from '@angular/core'; import { NavController, NavOptions } from 'ionic-angular'; +import { SafeUrl } from '@angular/platform-browser'; import { CoreEventsProvider } from '@providers/events'; import { CoreLoggerProvider } from '@providers/logger'; import { CoreSitesProvider } from '@providers/sites'; @@ -77,7 +78,7 @@ export interface CoreCourseModuleHandlerData { * The image to use as icon (path to the image). * @type {string} */ - icon?: string; + icon?: string | SafeUrl; /** * The class to assign to the item. From 9460133e0a075af28fdeebaa5fe73d9e0fe69f8b Mon Sep 17 00:00:00 2001 From: Dani Palou Date: Mon, 3 Sep 2018 16:45:39 +0200 Subject: [PATCH 5/9] MOBILE-2567 siteplugins: Fix error if initResult not defined --- src/core/siteplugins/providers/siteplugins.ts | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/core/siteplugins/providers/siteplugins.ts b/src/core/siteplugins/providers/siteplugins.ts index 2dab2bbf2..d8d5a4ab1 100644 --- a/src/core/siteplugins/providers/siteplugins.ts +++ b/src/core/siteplugins/providers/siteplugins.ts @@ -149,15 +149,19 @@ export class CoreSitePluginsProvider { * @return {any} An object with the data to pass to the JS. */ createDataForJS(initResult: any, contentResult?: any): any { - // First of all, add the data returned by the init JS (if any). - let data = this.utils.clone(initResult.jsResult || {}); - if (typeof data == 'boolean') { - data = {}; - } + let data; - // Now add some data returned by the init WS call. - data.INIT_TEMPLATES = this.utils.objectToKeyValueMap(initResult.templates, 'id', 'html'); - data.INIT_OTHERDATA = initResult.otherdata; + if (initResult) { + // First of all, add the data returned by the init JS (if any). + data = this.utils.clone(initResult.jsResult || {}); + if (typeof data == 'boolean') { + data = {}; + } + + // Now add some data returned by the init WS call. + data.INIT_TEMPLATES = this.utils.objectToKeyValueMap(initResult.templates, 'id', 'html'); + data.INIT_OTHERDATA = initResult.otherdata; + } if (contentResult) { // Now add the data returned by the content WS call. From ba463738732c3189a9ca1f18875290c193b6d27b Mon Sep 17 00:00:00 2001 From: Dani Palou Date: Tue, 4 Sep 2018 12:50:31 +0200 Subject: [PATCH 6/9] MOBILE-2567 core: Increase opacity of some disabled inputs --- src/theme/variables.scss | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/theme/variables.scss b/src/theme/variables.scss index 908caf8ec..10e70f4b2 100644 --- a/src/theme/variables.scss +++ b/src/theme/variables.scss @@ -149,6 +149,9 @@ $tabs-ios-tab-color-inactive: $tabs-tab-color-inactive; $button-ios-outline-background-color: $core-button-outline-background-color; $toolbar-ios-height: 44px + 8; // Avoid toolbar with different heights. $checkbox-ios-icon-border-radius: 0px !default; +$radio-ios-disabled-opacity: .5 !default; +$checkbox-ios-disabled-opacity: .5 !default; +$toggle-ios-disabled-opacity: .5 !default; // App Material Design Variables // -------------------------------------------------- @@ -163,6 +166,9 @@ $spinner-md-crescent-color: $core-spinner-color; $tabs-md-tab-color-inactive: $tabs-tab-color-inactive; $button-md-outline-background-color: $core-button-outline-background-color; $font-family-md-base: "Roboto", "Noto Sans", "Helvetica Neue", sans-serif !default; +$radio-md-disabled-opacity: .5 !default; +$checkbox-md-disabled-opacity: .5 !default; +$toggle-md-disabled-opacity: .5 !default; // App Windows Variables // -------------------------------------------------- @@ -175,7 +181,9 @@ $loading-wp-spinner-color: $core-loading-spinner-color; $spinner-wp-circles-color: $core-spinner-color; $tabs-wp-tab-color-inactive: $tabs-tab-color-inactive; $button-wp-outline-background-color: $core-button-outline-background-color; - +$radio-wp-disabled-opacity: .5 !default; +$checkbox-wp-disabled-opacity: .5 !default; +$toggle-wp-disabled-opacity: .5 !default; // App Theme // -------------------------------------------------- From b67a2900eb637041e97cfd59f4fccfcd304f5afd Mon Sep 17 00:00:00 2001 From: Dani Palou Date: Tue, 4 Sep 2018 16:16:19 +0200 Subject: [PATCH 7/9] MOBILE-2567 core: Fix local notification events --- config.xml | 2 +- src/providers/local-notifications.ts | 20 +++++++++++--------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/config.xml b/config.xml index f35f79a3a..33e6375ec 100644 --- a/config.xml +++ b/config.xml @@ -122,7 +122,7 @@ - + diff --git a/src/providers/local-notifications.ts b/src/providers/local-notifications.ts index 4002a066d..29ea131a2 100644 --- a/src/providers/local-notifications.ts +++ b/src/providers/local-notifications.ts @@ -125,17 +125,19 @@ export class CoreLocalNotificationsProvider { this.appDB = appProvider.getDB(); this.appDB.createTablesFromSchema(this.tablesSchema); - localNotifications.on('trigger', (notification, state) => { - this.trigger(notification); - }); + platform.ready().then(() => { + localNotifications.on('trigger', (notification, state) => { + this.trigger(notification); + }); - localNotifications.on('click', (notification, state) => { - if (notification && notification.data) { - this.logger.debug('Notification clicked: ', notification.data); + localNotifications.on('click', (notification, state) => { + if (notification && notification.data) { + this.logger.debug('Notification clicked: ', notification.data); - const data = textUtils.parseJSON(notification.data); - this.notifyClick(data); - } + const data = textUtils.parseJSON(notification.data); + this.notifyClick(data); + } + }); }); eventsProvider.on(CoreEventsProvider.SITE_DELETED, (site) => { From d15165ad986e42a86c6c3693858a31a15c6599ee Mon Sep 17 00:00:00 2001 From: Dani Palou Date: Wed, 5 Sep 2018 11:18:32 +0200 Subject: [PATCH 8/9] MOBILE-2567 database: Fix change detection with number fields --- src/addon/mod/data/fields/number/providers/handler.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/addon/mod/data/fields/number/providers/handler.ts b/src/addon/mod/data/fields/number/providers/handler.ts index 40663e8f0..fbf3fe68a 100644 --- a/src/addon/mod/data/fields/number/providers/handler.ts +++ b/src/addon/mod/data/fields/number/providers/handler.ts @@ -50,9 +50,10 @@ export class AddonModDataFieldNumberHandler extends AddonModDataFieldTextHandler */ hasFieldDataChanged(field: any, inputData: any, originalFieldData: any): Promise | boolean { const fieldName = 'f_' + field.id, - input = typeof inputData[fieldName] != 'undefined' ? parseFloat(inputData[fieldName]) : ''; + input = typeof inputData[fieldName] != 'undefined' && inputData[fieldName] !== null ? + parseFloat(inputData[fieldName]) : ''; - originalFieldData = (originalFieldData && typeof originalFieldData.content != 'undefined') ? + originalFieldData = (originalFieldData && typeof originalFieldData.content != 'undefined' && originalFieldData !== null) ? parseFloat(originalFieldData.content) : ''; return input != originalFieldData; From d6af09f799ed0bb933e4ae12e6d573f2a5df230e Mon Sep 17 00:00:00 2001 From: Dani Palou Date: Wed, 5 Sep 2018 11:34:40 +0200 Subject: [PATCH 9/9] MOBILE-2567 database: Display confirm before deleting an entry --- .../mod/data/providers/delete-link-handler.ts | 53 +++++++++++-------- 1 file changed, 30 insertions(+), 23 deletions(-) diff --git a/src/addon/mod/data/providers/delete-link-handler.ts b/src/addon/mod/data/providers/delete-link-handler.ts index 9338d7817..5ba8f1b31 100644 --- a/src/addon/mod/data/providers/delete-link-handler.ts +++ b/src/addon/mod/data/providers/delete-link-handler.ts @@ -13,6 +13,7 @@ // limitations under the License. import { Injectable } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; import { CoreContentLinksHandlerBase } from '@core/contentlinks/classes/base-handler'; import { CoreContentLinksAction } from '@core/contentlinks/providers/delegate'; import { AddonModDataProvider } from './data'; @@ -31,7 +32,8 @@ export class AddonModDataDeleteLinkHandler extends CoreContentLinksHandlerBase { pattern = /\/mod\/data\/view\.php.*([\?\&](d|delete)=\d+)/; constructor(private dataProvider: AddonModDataProvider, private courseProvider: CoreCourseProvider, - private domUtils: CoreDomUtilsProvider, private eventsProvider: CoreEventsProvider) { + private domUtils: CoreDomUtilsProvider, private eventsProvider: CoreEventsProvider, + private translate: TranslateService) { super(); } @@ -66,32 +68,37 @@ export class AddonModDataDeleteLinkHandler extends CoreContentLinksHandlerBase { CoreContentLinksAction[] | Promise { return [{ action: (siteId, navCtrl?): void => { - const modal = this.domUtils.showModalLoading(), - dataId = parseInt(params.d, 10), - entryId = parseInt(params.delete, 10); - this.getActivityCourseIdIfNotSet(dataId, siteId, courseId).then((cId) => { - courseId = cId; + this.domUtils.showConfirm(this.translate.instant('addon.mod_data.confirmdeleterecord')).then(() => { + const modal = this.domUtils.showModalLoading(), + dataId = parseInt(params.d, 10), + entryId = parseInt(params.delete, 10); - // Delete entry. - return this.dataProvider.deleteEntry(dataId, entryId, courseId, siteId).catch((message) => { - this.domUtils.showErrorModalDefault(message, 'addon.mod_data.errordeleting', true); + return this.getActivityCourseIdIfNotSet(dataId, siteId, courseId).then((cId) => { + courseId = cId; - return Promise.reject(null); + // Delete entry. + return this.dataProvider.deleteEntry(dataId, entryId, courseId, siteId).catch((message) => { + this.domUtils.showErrorModalDefault(message, 'addon.mod_data.errordeleting', true); + + return Promise.reject(null); + }); + }).then(() => { + const promises = []; + promises.push(this.dataProvider.invalidateEntryData(dataId, entryId, siteId)); + promises.push(this.dataProvider.invalidateEntriesData(dataId, siteId)); + + return Promise.all(promises); + }).then(() => { + this.eventsProvider.trigger(AddonModDataProvider.ENTRY_CHANGED, {dataId: dataId, entryId: entryId, + deleted: true}, siteId); + + this.domUtils.showToast('addon.mod_data.recorddeleted', true, 3000); + }).finally(() => { + modal.dismiss(); }); - }).then(() => { - const promises = []; - promises.push(this.dataProvider.invalidateEntryData(dataId, entryId, siteId)); - promises.push(this.dataProvider.invalidateEntriesData(dataId, siteId)); - - return Promise.all(promises); - }).then(() => { - this.eventsProvider.trigger(AddonModDataProvider.ENTRY_CHANGED, {dataId: dataId, entryId: entryId, - deleted: true}, siteId); - - this.domUtils.showToast('addon.mod_data.recorddeleted', true, 3000); - }).finally(() => { - modal.dismiss(); + }).catch(() => { + // Nothing to do. }); } }];