Merge pull request #1501 from dpalou/MOBILE-2567

Mobile 2567
main
Juan Leyva 2018-09-05 11:36:38 +02:00 committed by GitHub
commit b1839c6f1e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 81 additions and 68 deletions

View File

@ -122,7 +122,7 @@
</plugin>
<plugin name="ionic-plugin-keyboard" spec="^2.2.1" />
<plugin name="cordova-plugin-zip" spec="^3.1.0" />
<plugin name="cordova-plugin-local-notifications-mm" spec="^1.0.10" />
<plugin name="cordova-plugin-local-notifications-mm" spec="^1.0.11" />
<plugin name="cordova-plugin-file-opener2" spec="^2.0.19" />
<plugin name="com-darryncampbell-cordova-plugin-intent" spec="^1.1.0" />
<plugin name="cordova-sqlite-evcore-extbuild-free" spec="^0.9.7" />

View File

@ -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",

View File

@ -92,23 +92,6 @@ export class AddonModAssignSubmissionListPage implements OnInit, OnDestroy {
});
}
/**
* Check if we can leave the page or not.
*
* @return {boolean|Promise<void>} Resolved if we can leave it, rejected if not.
*/
ionViewCanLeave(): boolean | Promise<void> {
// 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.
*

View File

@ -50,9 +50,10 @@ export class AddonModDataFieldNumberHandler extends AddonModDataFieldTextHandler
*/
hasFieldDataChanged(field: any, inputData: any, originalFieldData: any): Promise<boolean> | 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;

View File

@ -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<CoreContentLinksAction[]> {
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.
});
}
}];

View File

@ -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);
}
});
}

View File

@ -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;

View File

@ -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.
*

View File

@ -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);

View File

@ -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.

View File

@ -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.

View File

@ -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) => {

View File

@ -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
// --------------------------------------------------