MOBILE-3087 calendar: Support editing calendar events
parent
98776a9c78
commit
e740fe4205
|
@ -1484,6 +1484,7 @@
|
|||
"core.image": "local_moodlemobileapp",
|
||||
"core.imageviewer": "local_moodlemobileapp",
|
||||
"core.info": "moodle",
|
||||
"core.invalidformdata": "error",
|
||||
"core.ios": "local_moodlemobileapp",
|
||||
"core.labelsep": "langconfig",
|
||||
"core.lastaccess": "moodle",
|
||||
|
|
|
@ -134,7 +134,7 @@
|
|||
<ion-col>
|
||||
<button ion-button block (click)="submit()" [disabled]="!eventForm.valid">{{ 'core.save' | translate }}</button>
|
||||
</ion-col>
|
||||
<ion-col *ngIf="hasOffline">
|
||||
<ion-col *ngIf="hasOffline && eventId < 0">
|
||||
<button ion-button block color="light" (click)="discard()">{{ 'core.discard' | translate }}</button>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
|
|
|
@ -162,7 +162,7 @@ export class AddonCalendarEditEventPage implements OnInit, OnDestroy {
|
|||
}
|
||||
|
||||
if (this.eventId && !refresh) {
|
||||
// If editing an event, get offline data. Wait for sync first.
|
||||
// Editing an event, get the event data. Wait for sync first.
|
||||
|
||||
promises.push(this.calendarSync.waitForSync(AddonCalendarSyncProvider.SYNC_ID).then(() => {
|
||||
// Do not block if the scope is already destroyed.
|
||||
|
@ -170,29 +170,38 @@ export class AddonCalendarEditEventPage implements OnInit, OnDestroy {
|
|||
this.syncProvider.blockOperation(AddonCalendarProvider.COMPONENT, this.eventId);
|
||||
}
|
||||
|
||||
// Get the event data if there's any.
|
||||
// Get the event offline data if there's any.
|
||||
return this.calendarOffline.getEvent(this.eventId).then((event) => {
|
||||
this.hasOffline = true;
|
||||
|
||||
// Load the data in the form.
|
||||
this.eventForm.controls.name.setValue(event.name);
|
||||
this.eventForm.controls.timestart.setValue(this.timeUtils.toDatetimeFormat(event.timestart * 1000));
|
||||
this.eventForm.controls.eventtype.setValue(event.eventtype);
|
||||
this.eventForm.controls.categoryid.setValue(event.categoryid || '');
|
||||
this.eventForm.controls.courseid.setValue(event.courseid || '');
|
||||
this.eventForm.controls.groupcourseid.setValue(event.groupcourseid || '');
|
||||
this.eventForm.controls.groupid.setValue(event.groupid || '');
|
||||
this.eventForm.controls.description.setValue(event.description);
|
||||
this.eventForm.controls.location.setValue(event.location);
|
||||
this.eventForm.controls.duration.setValue(event.duration);
|
||||
this.eventForm.controls.timedurationuntil.setValue(
|
||||
this.timeUtils.toDatetimeFormat((event.timedurationuntil * 1000) || Date.now()));
|
||||
this.eventForm.controls.timedurationminutes.setValue(event.timedurationminutes || '');
|
||||
this.eventForm.controls.repeat.setValue(!!event.repeat);
|
||||
this.eventForm.controls.repeats.setValue(event.repeats || '1');
|
||||
return event;
|
||||
}).catch(() => {
|
||||
// No offline data.
|
||||
this.hasOffline = false;
|
||||
|
||||
if (this.eventId > 0) {
|
||||
// It's an online event. get its data from server.
|
||||
return this.calendarProvider.getEventById(this.eventId);
|
||||
}
|
||||
}).then((event) => {
|
||||
if (event) {
|
||||
// Load the data in the form.
|
||||
this.eventForm.controls.name.setValue(event.name);
|
||||
this.eventForm.controls.timestart.setValue(this.timeUtils.toDatetimeFormat(event.timestart * 1000));
|
||||
this.eventForm.controls.eventtype.setValue(event.eventtype);
|
||||
this.eventForm.controls.categoryid.setValue(event.categoryid || '');
|
||||
this.eventForm.controls.courseid.setValue(event.courseid || '');
|
||||
this.eventForm.controls.groupcourseid.setValue(event.groupcourseid || '');
|
||||
this.eventForm.controls.groupid.setValue(event.groupid || '');
|
||||
this.eventForm.controls.description.setValue(event.description);
|
||||
this.eventForm.controls.location.setValue(event.location);
|
||||
this.eventForm.controls.duration.setValue(event.duration);
|
||||
this.eventForm.controls.timedurationuntil.setValue(
|
||||
this.timeUtils.toDatetimeFormat((event.timedurationuntil * 1000) || Date.now()));
|
||||
this.eventForm.controls.timedurationminutes.setValue(event.timedurationminutes || '');
|
||||
this.eventForm.controls.repeat.setValue(!!event.repeat);
|
||||
this.eventForm.controls.repeats.setValue(event.repeats || '1');
|
||||
}
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
@ -379,7 +388,7 @@ export class AddonCalendarEditEventPage implements OnInit, OnDestroy {
|
|||
}
|
||||
|
||||
// Send the data.
|
||||
const modal = this.domUtils.showModalLoading('core.sending');
|
||||
const modal = this.domUtils.showModalLoading('core.sending', true);
|
||||
|
||||
this.calendarProvider.submitEvent(this.eventId, data).then((result) => {
|
||||
this.returnToList(result.event);
|
||||
|
@ -399,13 +408,21 @@ export class AddonCalendarEditEventPage implements OnInit, OnDestroy {
|
|||
// Unblock the sync because the view will be destroyed and the sync process could be triggered before ngOnDestroy.
|
||||
this.unblockSync();
|
||||
|
||||
if (event) {
|
||||
if (this.eventId > 0) {
|
||||
// Editing an event.
|
||||
const data: any = {
|
||||
event: event
|
||||
};
|
||||
this.eventsProvider.trigger(AddonCalendarProvider.NEW_EVENT_EVENT, data, this.currentSite.getId());
|
||||
this.eventsProvider.trigger(AddonCalendarProvider.EDIT_EVENT_EVENT, data, this.currentSite.getId());
|
||||
} else {
|
||||
this.eventsProvider.trigger(AddonCalendarProvider.NEW_EVENT_DISCARDED_EVENT, {}, this.currentSite.getId());
|
||||
if (event) {
|
||||
const data: any = {
|
||||
event: event
|
||||
};
|
||||
this.eventsProvider.trigger(AddonCalendarProvider.NEW_EVENT_EVENT, data, this.currentSite.getId());
|
||||
} else {
|
||||
this.eventsProvider.trigger(AddonCalendarProvider.NEW_EVENT_DISCARDED_EVENT, {}, this.currentSite.getId());
|
||||
}
|
||||
}
|
||||
|
||||
if (this.svComponent && this.svComponent.isOn()) {
|
||||
|
|
|
@ -1,13 +1,27 @@
|
|||
<ion-header>
|
||||
<ion-navbar core-back-button>
|
||||
<ion-title><core-format-text [text]="title"></core-format-text></ion-title>
|
||||
<ion-buttons end>
|
||||
<!-- The context menu will be added in here. -->
|
||||
</ion-buttons>
|
||||
</ion-navbar>
|
||||
</ion-header>
|
||||
<core-navbar-buttons end>
|
||||
<core-context-menu>
|
||||
<core-context-menu-item [hidden]="isSplitViewOn || !eventLoaded || !hasOffline || !isOnline" [priority]="400" [content]="'core.settings.synchronizenow' | translate" (action)="doRefresh(null, $event, true)" [iconAction]="syncIcon" [closeOnClick]="false"></core-context-menu-item>
|
||||
<core-context-menu-item [hidden]="!canEdit || !event || !event.canedit" [priority]="300" [content]="'core.edit' | translate" (action)="openEdit()" [iconAction]="'create'"></core-context-menu-item>
|
||||
</core-context-menu>
|
||||
</core-navbar-buttons>
|
||||
<ion-content>
|
||||
<ion-refresher [enabled]="eventLoaded" (ionRefresh)="refreshEvent($event)">
|
||||
<ion-refresher [enabled]="eventLoaded" (ionRefresh)="doRefresh($event)">
|
||||
<ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
|
||||
</ion-refresher>
|
||||
<core-loading [hideUntil]="eventLoaded">
|
||||
<!-- There is data to be synchronized -->
|
||||
<ion-card class="core-warning-card" icon-start *ngIf="hasOffline">
|
||||
<ion-icon name="warning"></ion-icon> {{ 'core.hasdatatosync' | translate:{$a: 'addon.calendar.calendarevent' | translate} }}
|
||||
</ion-card>
|
||||
|
||||
<ion-card>
|
||||
<ion-card-content *ngIf="event">
|
||||
<ion-item text-wrap>
|
||||
|
|
|
@ -12,12 +12,16 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { Component, ViewChild } from '@angular/core';
|
||||
import { IonicPage, Content, NavParams } from 'ionic-angular';
|
||||
import { Component, ViewChild, Optional, OnDestroy, NgZone } from '@angular/core';
|
||||
import { IonicPage, Content, NavParams, NavController } from 'ionic-angular';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { AddonCalendarProvider } from '../../providers/calendar';
|
||||
import { AddonCalendarHelperProvider } from '../../providers/helper';
|
||||
import { AddonCalendarOfflineProvider } from '../../providers/calendar-offline';
|
||||
import { AddonCalendarSyncProvider } from '../../providers/calendar-sync';
|
||||
import { CoreCoursesProvider } from '@core/courses/providers/courses';
|
||||
import { CoreAppProvider } from '@providers/app';
|
||||
import { CoreEventsProvider } from '@providers/events';
|
||||
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
||||
import { CoreTextUtilsProvider } from '@providers/utils/text';
|
||||
import { CoreSitesProvider } from '@providers/sites';
|
||||
|
@ -25,6 +29,8 @@ import { CoreLocalNotificationsProvider } from '@providers/local-notifications';
|
|||
import { CoreCourseProvider } from '@core/course/providers/course';
|
||||
import { CoreTimeUtilsProvider } from '@providers/utils/time';
|
||||
import { CoreGroupsProvider } from '@providers/groups';
|
||||
import { CoreSplitViewComponent } from '@components/split-view/split-view';
|
||||
import { Network } from '@ionic-native/network';
|
||||
|
||||
/**
|
||||
* Page that displays a single calendar event.
|
||||
|
@ -34,11 +40,17 @@ import { CoreGroupsProvider } from '@providers/groups';
|
|||
selector: 'page-addon-calendar-event',
|
||||
templateUrl: 'event.html',
|
||||
})
|
||||
export class AddonCalendarEventPage {
|
||||
export class AddonCalendarEventPage implements OnDestroy {
|
||||
@ViewChild(Content) content: Content;
|
||||
|
||||
protected eventId;
|
||||
protected siteHomeId: number;
|
||||
protected editEventObserver: any;
|
||||
protected syncObserver: any;
|
||||
protected manualSyncObserver: any;
|
||||
protected onlineObserver: any;
|
||||
protected currentSiteId: string;
|
||||
|
||||
eventLoaded: boolean;
|
||||
notificationFormat: string;
|
||||
notificationMin: string;
|
||||
|
@ -55,17 +67,31 @@ export class AddonCalendarEventPage {
|
|||
currentTime: number;
|
||||
defaultTime: number;
|
||||
reminders: any[];
|
||||
canEdit = false;
|
||||
hasOffline = false;
|
||||
isOnline = false;
|
||||
syncIcon: string; // Sync icon.
|
||||
isSplitViewOn = false;
|
||||
|
||||
constructor(private translate: TranslateService, private calendarProvider: AddonCalendarProvider, navParams: NavParams,
|
||||
private domUtils: CoreDomUtilsProvider, private coursesProvider: CoreCoursesProvider,
|
||||
private calendarHelper: AddonCalendarHelperProvider, private sitesProvider: CoreSitesProvider,
|
||||
localNotificationsProvider: CoreLocalNotificationsProvider, private courseProvider: CoreCourseProvider,
|
||||
private textUtils: CoreTextUtilsProvider, private timeUtils: CoreTimeUtilsProvider,
|
||||
private groupsProvider: CoreGroupsProvider) {
|
||||
private groupsProvider: CoreGroupsProvider, @Optional() private svComponent: CoreSplitViewComponent,
|
||||
private navCtrl: NavController, private eventsProvider: CoreEventsProvider, network: Network, zone: NgZone,
|
||||
private calendarSync: AddonCalendarSyncProvider, private appProvider: CoreAppProvider,
|
||||
private calendarOffline: AddonCalendarOfflineProvider) {
|
||||
|
||||
this.eventId = navParams.get('id');
|
||||
this.notificationsEnabled = localNotificationsProvider.isAvailable();
|
||||
this.siteHomeId = sitesProvider.getCurrentSite().getSiteHomeId();
|
||||
this.currentSiteId = sitesProvider.getCurrentSiteId();
|
||||
this.isSplitViewOn = this.svComponent && this.svComponent.isOn();
|
||||
|
||||
// Check if site supports editing. No need to check allowed types, event.canedit already does it.
|
||||
this.canEdit = this.calendarProvider.canEditEventsInSite();
|
||||
|
||||
if (this.notificationsEnabled) {
|
||||
this.calendarProvider.getEventReminders(this.eventId).then((reminders) => {
|
||||
this.reminders = reminders;
|
||||
|
@ -79,34 +105,105 @@ export class AddonCalendarEventPage {
|
|||
this.notificationFormat = this.timeUtils.fixFormatForDatetime(this.timeUtils.convertPHPToMoment(
|
||||
this.translate.instant('core.strftimedatetime')));
|
||||
}
|
||||
|
||||
// Listen for event edited. If current event is edited, reload the data.
|
||||
this.editEventObserver = eventsProvider.on(AddonCalendarProvider.EDIT_EVENT_EVENT, (data) => {
|
||||
if (data && data.event && data.event.id == this.eventId) {
|
||||
this.eventLoaded = false;
|
||||
this.refreshEvent(true, false);
|
||||
}
|
||||
}, this.currentSiteId);
|
||||
|
||||
// Refresh data if this calendar event is synchronized automatically.
|
||||
this.syncObserver = eventsProvider.on(AddonCalendarSyncProvider.AUTO_SYNCED, this.checkSyncResult.bind(this, false),
|
||||
this.currentSiteId);
|
||||
|
||||
// Refresh data if calendar events are synchronized manually but not by this page.
|
||||
this.manualSyncObserver = eventsProvider.on(AddonCalendarSyncProvider.MANUAL_SYNCED, this.checkSyncResult.bind(this, true),
|
||||
this.currentSiteId);
|
||||
|
||||
// Refresh online status when changes.
|
||||
this.onlineObserver = network.onchange().subscribe((online) => {
|
||||
// Execute the callback in the Angular zone, so change detection doesn't stop working.
|
||||
zone.run(() => {
|
||||
this.isOnline = online;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* View loaded.
|
||||
*/
|
||||
ionViewDidLoad(): void {
|
||||
this.fetchEvent().finally(() => {
|
||||
this.eventLoaded = true;
|
||||
});
|
||||
this.syncIcon = 'spinner';
|
||||
|
||||
this.fetchEvent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the event and updates the view.
|
||||
*
|
||||
* @param {boolean} [sync] Whether it should try to synchronize offline events.
|
||||
* @param {boolean} [showErrors] Whether to show sync errors to the user.
|
||||
* @return {Promise<any>} Promise resolved when done.
|
||||
*/
|
||||
fetchEvent(): Promise<any> {
|
||||
fetchEvent(sync?: boolean, showErrors?: boolean): Promise<any> {
|
||||
const currentSite = this.sitesProvider.getCurrentSite(),
|
||||
canGetById = this.calendarProvider.isGetEventByIdAvailable();
|
||||
let promise;
|
||||
|
||||
if (canGetById) {
|
||||
promise = this.calendarProvider.getEventById(this.eventId);
|
||||
this.isOnline = this.appProvider.isOnline();
|
||||
|
||||
if (sync) {
|
||||
// Try to synchronize offline events.
|
||||
promise = this.calendarSync.syncEvents().then((result) => {
|
||||
if (result.warnings && result.warnings.length) {
|
||||
this.domUtils.showErrorModal(result.warnings[0]);
|
||||
}
|
||||
|
||||
if (result.updated) {
|
||||
// Trigger a manual sync event.
|
||||
result.source = 'event';
|
||||
|
||||
this.eventsProvider.trigger(AddonCalendarSyncProvider.MANUAL_SYNCED, result, this.currentSiteId);
|
||||
}
|
||||
}).catch((error) => {
|
||||
if (showErrors) {
|
||||
this.domUtils.showErrorModalDefault(error, 'core.errorsync', true);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
promise = this.calendarProvider.getEvent(this.eventId);
|
||||
promise = Promise.resolve();
|
||||
}
|
||||
|
||||
return promise.then((event) => {
|
||||
return promise.then(() => {
|
||||
const promises = [];
|
||||
|
||||
// Get the event data.
|
||||
if (canGetById) {
|
||||
promises.push(this.calendarProvider.getEventById(this.eventId));
|
||||
} else {
|
||||
promises.push(this.calendarProvider.getEvent(this.eventId));
|
||||
}
|
||||
|
||||
// Get offline data.
|
||||
promises.push(this.calendarOffline.getEvent(this.eventId).catch(() => {
|
||||
// No offline data.
|
||||
}));
|
||||
|
||||
return Promise.all(promises).then((results) => {
|
||||
if (results[1]) {
|
||||
// There is offline data, apply it.
|
||||
this.hasOffline = true;
|
||||
Object.assign(results[0], results[1]);
|
||||
} else {
|
||||
this.hasOffline = false;
|
||||
}
|
||||
|
||||
return results[0];
|
||||
});
|
||||
|
||||
}).then((event) => {
|
||||
const promises = [];
|
||||
|
||||
this.calendarHelper.formatEventData(event);
|
||||
|
@ -196,6 +293,9 @@ export class AddonCalendarEventPage {
|
|||
return Promise.all(promises);
|
||||
}).catch((error) => {
|
||||
this.domUtils.showErrorModalDefault(error, 'addon.calendar.errorloadevent', true);
|
||||
}).finally(() => {
|
||||
this.eventLoaded = true;
|
||||
this.syncIcon = 'sync';
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -246,16 +346,77 @@ export class AddonCalendarEventPage {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh the data.
|
||||
*
|
||||
* @param {any} [refresher] Refresher.
|
||||
* @param {Function} [done] Function to call when done.
|
||||
* @param {boolean} [showErrors] Whether to show sync errors to the user.
|
||||
* @return {Promise<any>} Promise resolved when done.
|
||||
*/
|
||||
doRefresh(refresher?: any, done?: () => void, showErrors?: boolean): Promise<any> {
|
||||
if (this.eventLoaded) {
|
||||
return this.refreshEvent(true, showErrors).finally(() => {
|
||||
refresher && refresher.complete();
|
||||
done && done();
|
||||
});
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh the event.
|
||||
*
|
||||
* @param {any} refresher Refresher.
|
||||
* @param {boolean} [sync] Whether it should try to synchronize offline events.
|
||||
* @param {boolean} [showErrors] Whether to show sync errors to the user.
|
||||
* @return {Promise<any>} Promise resolved when done.
|
||||
*/
|
||||
refreshEvent(refresher: any): void {
|
||||
this.calendarProvider.invalidateEvent(this.eventId).finally(() => {
|
||||
this.fetchEvent().finally(() => {
|
||||
refresher.complete();
|
||||
});
|
||||
refreshEvent(sync?: boolean, showErrors?: boolean): Promise<any> {
|
||||
this.syncIcon = 'spinner';
|
||||
|
||||
return this.calendarProvider.invalidateEvent(this.eventId).catch(() => {
|
||||
// Ignore errors.
|
||||
}).then(() => {
|
||||
return this.fetchEvent(sync, showErrors);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the page to edit the event.
|
||||
*/
|
||||
openEdit(): void {
|
||||
// Decide which navCtrl to use. If this page is inside a split view, use the split view's master nav.
|
||||
const navCtrl = this.svComponent ? this.svComponent.getMasterNav() : this.navCtrl;
|
||||
navCtrl.push('AddonCalendarEditEventPage', {eventId: this.eventId});
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the result of an automatic sync or a manual sync not done by this page.
|
||||
*
|
||||
* @param {boolean} isManual Whether it's a manual sync.
|
||||
* @param {any} data Sync result.
|
||||
*/
|
||||
protected checkSyncResult(isManual: boolean, data: any): void {
|
||||
if (data && data.events && (!isManual || data.source != 'event')) {
|
||||
const event = data.events.find((ev) => {
|
||||
return ev.id == this.eventId;
|
||||
});
|
||||
|
||||
if (event) {
|
||||
this.eventLoaded = false;
|
||||
this.refreshEvent();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Page destroyed.
|
||||
*/
|
||||
ngOnDestroy(): void {
|
||||
this.editEventObserver && this.editEventObserver.off();
|
||||
this.syncObserver && this.syncObserver.off();
|
||||
this.manualSyncObserver && this.manualSyncObserver.off();
|
||||
this.onlineObserver && this.onlineObserver.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
</button>
|
||||
<core-context-menu>
|
||||
<core-context-menu-item [hidden]="!notificationsEnabled" [priority]="600" [content]="'core.settings.settings' | translate" (action)="openSettings()" [iconAction]="'cog'"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="eventsLoaded && hasOffline && isOnline" [priority]="400" [content]="'core.settings.synchronizenow' | translate" (action)="doRefresh(null, $event, true)" [iconAction]="syncIcon" [closeOnClick]="false"></core-context-menu-item>
|
||||
<core-context-menu-item [hidden]="!eventsLoaded || !hasOffline || !isOnline" [priority]="400" [content]="'core.settings.synchronizenow' | translate" (action)="doRefresh(null, $event, true)" [iconAction]="syncIcon" [closeOnClick]="false"></core-context-menu-item>
|
||||
</core-context-menu>
|
||||
</ion-buttons>
|
||||
</ion-navbar>
|
||||
|
|
|
@ -59,8 +59,11 @@ export class AddonCalendarListPage implements OnDestroy {
|
|||
protected preSelectedCourseId: number;
|
||||
protected newEventObserver: any;
|
||||
protected discardedObserver: any;
|
||||
protected editEventObserver: any;
|
||||
protected syncObserver: any;
|
||||
protected manualSyncObserver: any;
|
||||
protected onlineObserver: any;
|
||||
protected currentSiteId: string;
|
||||
|
||||
courses: any[];
|
||||
eventsLoaded = false;
|
||||
|
@ -80,7 +83,7 @@ export class AddonCalendarListPage implements OnDestroy {
|
|||
|
||||
constructor(private translate: TranslateService, private calendarProvider: AddonCalendarProvider, navParams: NavParams,
|
||||
private domUtils: CoreDomUtilsProvider, private coursesProvider: CoreCoursesProvider, private utils: CoreUtilsProvider,
|
||||
private calendarHelper: AddonCalendarHelperProvider, private sitesProvider: CoreSitesProvider, zone: NgZone,
|
||||
private calendarHelper: AddonCalendarHelperProvider, sitesProvider: CoreSitesProvider, zone: NgZone,
|
||||
localNotificationsProvider: CoreLocalNotificationsProvider, private popoverCtrl: PopoverController,
|
||||
private eventsProvider: CoreEventsProvider, private navCtrl: NavController, private appProvider: CoreAppProvider,
|
||||
private calendarOffline: AddonCalendarOfflineProvider, private calendarSync: AddonCalendarSyncProvider,
|
||||
|
@ -88,12 +91,13 @@ export class AddonCalendarListPage implements OnDestroy {
|
|||
|
||||
this.siteHomeId = sitesProvider.getCurrentSite().getSiteHomeId();
|
||||
this.notificationsEnabled = localNotificationsProvider.isAvailable();
|
||||
this.currentSiteId = sitesProvider.getCurrentSiteId();
|
||||
|
||||
if (this.notificationsEnabled) {
|
||||
// Re-schedule events if default time changes.
|
||||
this.obsDefaultTimeChange = eventsProvider.on(AddonCalendarProvider.DEFAULT_NOTIFICATION_TIME_CHANGED, () => {
|
||||
calendarProvider.scheduleEventsNotifications(this.events);
|
||||
}, sitesProvider.getCurrentSiteId());
|
||||
}, this.currentSiteId);
|
||||
}
|
||||
|
||||
this.eventId = navParams.get('eventId') || false;
|
||||
|
@ -116,7 +120,7 @@ export class AddonCalendarListPage implements OnDestroy {
|
|||
}
|
||||
});
|
||||
}
|
||||
}, sitesProvider.getCurrentSiteId());
|
||||
}, this.currentSiteId);
|
||||
|
||||
// Listen for new event discarded event. When it does, reload the data.
|
||||
this.discardedObserver = eventsProvider.on(AddonCalendarProvider.NEW_EVENT_DISCARDED_EVENT, () => {
|
||||
|
@ -127,13 +131,29 @@ export class AddonCalendarListPage implements OnDestroy {
|
|||
|
||||
this.eventsLoaded = false;
|
||||
this.refreshEvents(true, false);
|
||||
}, sitesProvider.getCurrentSiteId());
|
||||
}, this.currentSiteId);
|
||||
|
||||
// Listen for events edited. When an event is edited, reload the data.
|
||||
this.editEventObserver = eventsProvider.on(AddonCalendarProvider.EDIT_EVENT_EVENT, (data) => {
|
||||
if (data && data.event) {
|
||||
this.eventsLoaded = false;
|
||||
this.refreshEvents(true, false);
|
||||
}
|
||||
}, this.currentSiteId);
|
||||
|
||||
// Refresh data if calendar events are synchronized automatically.
|
||||
this.syncObserver = eventsProvider.on(AddonCalendarSyncProvider.AUTO_SYNCED, (data) => {
|
||||
this.eventsLoaded = false;
|
||||
this.refreshEvents();
|
||||
}, sitesProvider.getCurrentSiteId());
|
||||
}, this.currentSiteId);
|
||||
|
||||
// Refresh data if calendar events are synchronized manually but not by this page.
|
||||
this.manualSyncObserver = eventsProvider.on(AddonCalendarSyncProvider.MANUAL_SYNCED, (data) => {
|
||||
if (data && data.source != 'list') {
|
||||
this.eventsLoaded = false;
|
||||
this.refreshEvents();
|
||||
}
|
||||
}, this.currentSiteId);
|
||||
|
||||
// Refresh online status when changes.
|
||||
this.onlineObserver = network.onchange().subscribe((online) => {
|
||||
|
@ -187,9 +207,9 @@ export class AddonCalendarListPage implements OnDestroy {
|
|||
|
||||
if (result.updated) {
|
||||
// Trigger a manual sync event.
|
||||
this.eventsProvider.trigger(AddonCalendarSyncProvider.MANUAL_SYNCED, {
|
||||
source: 'list'
|
||||
}, this.sitesProvider.getCurrentSiteId());
|
||||
result.source = 'list';
|
||||
|
||||
this.eventsProvider.trigger(AddonCalendarSyncProvider.MANUAL_SYNCED, result, this.currentSiteId);
|
||||
}
|
||||
}).catch((error) => {
|
||||
if (showErrors) {
|
||||
|
@ -530,6 +550,8 @@ export class AddonCalendarListPage implements OnDestroy {
|
|||
* @param {number} [eventId] Event ID to edit.
|
||||
*/
|
||||
openEdit(eventId?: number): void {
|
||||
this.eventId = undefined;
|
||||
|
||||
const params: any = {};
|
||||
|
||||
if (eventId) {
|
||||
|
@ -574,7 +596,9 @@ export class AddonCalendarListPage implements OnDestroy {
|
|||
this.obsDefaultTimeChange && this.obsDefaultTimeChange.off();
|
||||
this.newEventObserver && this.newEventObserver.off();
|
||||
this.discardedObserver && this.discardedObserver.off();
|
||||
this.editEventObserver && this.editEventObserver.off();
|
||||
this.syncObserver && this.syncObserver.off();
|
||||
this.onlineObserver && this.onlineObserver.off();
|
||||
this.manualSyncObserver && this.manualSyncObserver.off();
|
||||
this.onlineObserver && this.onlineObserver.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,8 +37,6 @@ export class AddonCalendarSyncProvider extends CoreSyncBaseProvider {
|
|||
static MANUAL_SYNCED = 'addon_calendar_manual_synced';
|
||||
static SYNC_ID = 'calendar';
|
||||
|
||||
protected componentTranslate: string;
|
||||
|
||||
constructor(translate: TranslateService,
|
||||
appProvider: CoreAppProvider,
|
||||
courseProvider: CoreCourseProvider,
|
||||
|
@ -54,8 +52,6 @@ export class AddonCalendarSyncProvider extends CoreSyncBaseProvider {
|
|||
|
||||
super('AddonCalendarSyncProvider', loggerProvider, sitesProvider, appProvider, syncProvider, textUtils, translate,
|
||||
timeUtils);
|
||||
|
||||
this.componentTranslate = this.translate.instant('addon.calendar.calendarevent');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -66,7 +62,7 @@ export class AddonCalendarSyncProvider extends CoreSyncBaseProvider {
|
|||
* @return {Promise<any>} Promise resolved if sync is successful, rejected if sync fails.
|
||||
*/
|
||||
syncAllEvents(siteId?: string, force?: boolean): Promise<any> {
|
||||
return this.syncOnSites('all calendars', this.syncAllEventsFunc.bind(this), [force], siteId);
|
||||
return this.syncOnSites('all calendar events', this.syncAllEventsFunc.bind(this), [force], siteId);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -77,6 +73,7 @@ export class AddonCalendarSyncProvider extends CoreSyncBaseProvider {
|
|||
* @return {Promise<any>} Promise resolved if sync is successful, rejected if sync fails.
|
||||
*/
|
||||
protected syncAllEventsFunc(siteId: string, force?: boolean): Promise<any> {
|
||||
|
||||
const promise = force ? this.syncEvents(siteId) : this.syncEventsIfNeeded(siteId);
|
||||
|
||||
return promise.then((result) => {
|
||||
|
@ -196,7 +193,8 @@ export class AddonCalendarSyncProvider extends CoreSyncBaseProvider {
|
|||
if (this.syncProvider.isBlocked(AddonCalendarProvider.COMPONENT, event.id, siteId)) {
|
||||
this.logger.debug('Cannot sync event ' + event.name + ' because it is blocked.');
|
||||
|
||||
return Promise.reject(this.translate.instant('core.errorsyncblocked', {$a: this.componentTranslate}));
|
||||
return Promise.reject(this.translate.instant('core.errorsyncblocked',
|
||||
{$a: this.translate.instant('addon.calendar.calendarevent')}));
|
||||
}
|
||||
|
||||
// Try to send the data.
|
||||
|
@ -216,7 +214,7 @@ export class AddonCalendarSyncProvider extends CoreSyncBaseProvider {
|
|||
return this.calendarOffline.deleteEvent(event.id, siteId).then(() => {
|
||||
// Event deleted, add a warning.
|
||||
result.warnings.push(this.translate.instant('core.warningofflinedatadeleted', {
|
||||
component: this.componentTranslate,
|
||||
component: this.translate.instant('addon.calendar.calendarevent'),
|
||||
name: event.name,
|
||||
error: this.textUtils.getErrorMessageFromError(error)
|
||||
}));
|
||||
|
|
|
@ -27,6 +27,7 @@ import { CoreConfigProvider } from '@providers/config';
|
|||
import { ILocalNotification } from '@ionic-native/local-notifications';
|
||||
import { SQLiteDB } from '@classes/sqlitedb';
|
||||
import { AddonCalendarOfflineProvider } from './calendar-offline';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
|
||||
/**
|
||||
* Service to handle calendar events.
|
||||
|
@ -40,6 +41,7 @@ export class AddonCalendarProvider {
|
|||
static DEFAULT_NOTIFICATION_TIME = 60;
|
||||
static NEW_EVENT_EVENT = 'addon_calendar_new_event';
|
||||
static NEW_EVENT_DISCARDED_EVENT = 'addon_calendar_new_event_discarded';
|
||||
static EDIT_EVENT_EVENT = 'addon_calendar_edit_event';
|
||||
static TYPE_CATEGORY = 'category';
|
||||
static TYPE_COURSE = 'course';
|
||||
static TYPE_GROUP = 'group';
|
||||
|
@ -218,7 +220,7 @@ export class AddonCalendarProvider {
|
|||
private coursesProvider: CoreCoursesProvider, private timeUtils: CoreTimeUtilsProvider,
|
||||
private localNotificationsProvider: CoreLocalNotificationsProvider, private configProvider: CoreConfigProvider,
|
||||
private utils: CoreUtilsProvider, private calendarOffline: AddonCalendarOfflineProvider,
|
||||
private appProvider: CoreAppProvider) {
|
||||
private appProvider: CoreAppProvider, private translate: TranslateService) {
|
||||
this.logger = logger.getInstance('AddonCalendarProvider');
|
||||
this.sitesProvider.registerSiteSchema(this.siteSchema);
|
||||
}
|
||||
|
@ -980,7 +982,12 @@ export class AddonCalendarProvider {
|
|||
formData.userid = site.getUserId();
|
||||
formData.visible = 1;
|
||||
formData.instance = 0;
|
||||
formData['_qf__core_calendar_local_event_forms_create'] = 1;
|
||||
|
||||
if (eventId > 0) {
|
||||
formData['_qf__core_calendar_local_event_forms_update'] = 1;
|
||||
} else {
|
||||
formData['_qf__core_calendar_local_event_forms_create'] = 1;
|
||||
}
|
||||
|
||||
const params = {
|
||||
formdata: this.utils.objectToGetParams(formData)
|
||||
|
@ -988,7 +995,11 @@ export class AddonCalendarProvider {
|
|||
|
||||
return site.write('core_calendar_submit_create_update_form', params).then((result) => {
|
||||
if (result.validationerror) {
|
||||
return Promise.reject(this.utils.createFakeWSError(''));
|
||||
// Simulate a WS error.
|
||||
return Promise.reject({
|
||||
message: this.translate.instant('core.invalidformdata'),
|
||||
errorcode: 'validationerror'
|
||||
});
|
||||
}
|
||||
|
||||
return result.event;
|
||||
|
|
|
@ -1484,6 +1484,7 @@
|
|||
"core.image": "Image",
|
||||
"core.imageviewer": "Image viewer",
|
||||
"core.info": "Information",
|
||||
"core.invalidformdata": "Incorrect form data",
|
||||
"core.ios": "iOS",
|
||||
"core.labelsep": ":",
|
||||
"core.lastaccess": "Last access",
|
||||
|
|
|
@ -117,6 +117,7 @@
|
|||
"image": "Image",
|
||||
"imageviewer": "Image viewer",
|
||||
"info": "Information",
|
||||
"invalidformdata": "Incorrect form data",
|
||||
"ios": "iOS",
|
||||
"labelsep": ":",
|
||||
"lastaccess": "Last access",
|
||||
|
|
|
@ -1058,7 +1058,7 @@ export class CoreUtilsProvider {
|
|||
* Convert an object to a format of GET param. E.g.: {a: 1, b: 2} -> a=1&b=2
|
||||
*
|
||||
* @param {any} object Object to convert.
|
||||
* @param {boolean} [removeEmpty=true] Whether to remove params whose value is empty/null/undefined.
|
||||
* @param {boolean} [removeEmpty=true] Whether to remove params whose value is null/undefined.
|
||||
* @return {string} GET params.
|
||||
*/
|
||||
objectToGetParams(object: any, removeEmpty: boolean = true): string {
|
||||
|
@ -1070,7 +1070,7 @@ export class CoreUtilsProvider {
|
|||
for (const name in flattened) {
|
||||
let value = flattened[name];
|
||||
|
||||
if (removeEmpty && (value === null || typeof value == 'undefined' || value === '')) {
|
||||
if (removeEmpty && (value === null || typeof value == 'undefined')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue