Merge pull request #2059 from dpalou/MOBILE-3090

MOBILE-3090 calendar: Improve invalidate data after sync
main
Juan Leyva 2019-08-20 08:46:42 +01:00 committed by GitHub
commit 373a4d0cc7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 126 additions and 66 deletions

View File

@ -479,7 +479,7 @@ export class AddonCalendarEditEventPage implements OnInit, OnDestroy {
} }
if (formData.repeat) { if (formData.repeat) {
data.repeats = formData.repeats; data.repeats = Number(formData.repeats);
} }
if (this.event && this.event.repeatid) { if (this.event && this.event.repeatid) {
@ -489,15 +489,22 @@ export class AddonCalendarEditEventPage implements OnInit, OnDestroy {
// Send the data. // Send the data.
const modal = this.domUtils.showModalLoading('core.sending', true); const modal = this.domUtils.showModalLoading('core.sending', true);
let event;
this.calendarProvider.submitEvent(this.eventId, data).then((result) => { this.calendarProvider.submitEvent(this.eventId, data).then((result) => {
const numberOfRepetitions = formData.repeat ? formData.repeats : event = result.event;
(data.repeateditall && this.event.othereventscount ? this.event.othereventscount + 1 : 1);
this.calendarHelper.invalidateRepeatedEventsOnCalendar(result.event, numberOfRepetitions).catch(() => { if (result.sent) {
// Ignore errors. // Event created or edited, invalidate right days & months.
}).then(() => { const numberOfRepetitions = formData.repeat ? formData.repeats :
this.returnToList(result.event); (data.repeateditall && this.event.othereventscount ? this.event.othereventscount + 1 : 1);
});
this.calendarHelper.invalidateRepeatedEventsOnCalendarForEvent(result.event, numberOfRepetitions).catch(() => {
// Ignore errors.
});
}
}).then(() => {
this.returnToList(event);
}).catch((error) => { }).catch((error) => {
this.domUtils.showErrorModalDefault(error, 'Error sending data.'); this.domUtils.showErrorModalDefault(error, 'Error sending data.');
}).finally(() => { }).finally(() => {

View File

@ -445,10 +445,19 @@ export class AddonCalendarEventPage implements OnDestroy {
const modal = this.domUtils.showModalLoading('core.sending', true); const modal = this.domUtils.showModalLoading('core.sending', true);
this.calendarProvider.deleteEvent(this.event.id, this.event.name, deleteAll).then((sent) => { this.calendarProvider.deleteEvent(this.event.id, this.event.name, deleteAll).then((sent) => {
this.calendarHelper.invalidateRepeatedEventsOnCalendar(this.event, deleteAll ? this.event.eventcount : 1) let promise;
.catch(() => {
// Ignore errors. if (sent) {
}).then(() => { // Event deleted, invalidate right days & months.
promise = this.calendarHelper.invalidateRepeatedEventsOnCalendarForEvent(this.event,
deleteAll ? this.event.eventcount : 1).catch(() => {
// Ignore errors.
});
} else {
promise = Promise.resolve();
}
return promise.then(() => {
// Trigger an event. // Trigger an event.
this.eventsProvider.trigger(AddonCalendarProvider.DELETED_EVENT_EVENT, { this.eventsProvider.trigger(AddonCalendarProvider.DELETED_EVENT_EVENT, {
eventId: this.eventId, eventId: this.eventId,

View File

@ -95,7 +95,7 @@ export class AddonCalendarOfflineProvider {
}, },
{ {
name: 'repeats', name: 'repeats',
type: 'TEXT', type: 'INTEGER',
}, },
{ {
name: 'repeatid', name: 'repeatid',

View File

@ -26,6 +26,7 @@ import { CoreTimeUtilsProvider } from '@providers/utils/time';
import { CoreUtilsProvider } from '@providers/utils/utils'; import { CoreUtilsProvider } from '@providers/utils/utils';
import { AddonCalendarProvider } from './calendar'; import { AddonCalendarProvider } from './calendar';
import { AddonCalendarOfflineProvider } from './calendar-offline'; import { AddonCalendarOfflineProvider } from './calendar-offline';
import { AddonCalendarHelperProvider } from './helper';
/** /**
* Service to sync calendar. * Service to sync calendar.
@ -48,7 +49,8 @@ export class AddonCalendarSyncProvider extends CoreSyncBaseProvider {
timeUtils: CoreTimeUtilsProvider, timeUtils: CoreTimeUtilsProvider,
private utils: CoreUtilsProvider, private utils: CoreUtilsProvider,
private calendarProvider: AddonCalendarProvider, private calendarProvider: AddonCalendarProvider,
private calendarOffline: AddonCalendarOfflineProvider) { private calendarOffline: AddonCalendarOfflineProvider,
private calendarHelper: AddonCalendarHelperProvider) {
super('AddonCalendarSyncProvider', loggerProvider, sitesProvider, appProvider, syncProvider, textUtils, translate, super('AddonCalendarSyncProvider', loggerProvider, sitesProvider, appProvider, syncProvider, textUtils, translate,
timeUtils); timeUtils);
@ -124,6 +126,7 @@ export class AddonCalendarSyncProvider extends CoreSyncBaseProvider {
warnings: [], warnings: [],
events: [], events: [],
deleted: [], deleted: [],
toinvalidate: [],
updated: false updated: false
}; };
let offlineEventIds: number[]; let offlineEventIds: number[];
@ -152,18 +155,13 @@ export class AddonCalendarSyncProvider extends CoreSyncBaseProvider {
return this.utils.allPromises(promises); return this.utils.allPromises(promises);
}).then(() => { }).then(() => {
if (result.updated) { if (result.updated) {
// Data has been sent to server. Now invalidate the WS calls. // Data has been sent to server. Now invalidate the WS calls.
const promises = [ const promises = [
this.calendarProvider.invalidateEventsList(siteId), this.calendarProvider.invalidateEventsList(siteId),
this.calendarHelper.invalidateRepeatedEventsOnCalendar(result.toinvalidate, siteId)
]; ];
offlineEventIds.forEach((eventId) => {
if (eventId > 0) {
// An event was edited, invalidate its data too.
promises.push(this.calendarProvider.invalidateEvent(eventId, siteId));
}
});
return Promise.all(promises).catch(() => { return Promise.all(promises).catch(() => {
// Ignore errors. // Ignore errors.
}); });
@ -214,6 +212,16 @@ export class AddonCalendarSyncProvider extends CoreSyncBaseProvider {
// Ignore errors, maybe there was no edit data. // Ignore errors, maybe there was no edit data.
})); }));
// We need the event data to invalidate it. Get it from local DB.
promises.push(this.calendarProvider.getEventFromLocalDb(eventId, siteId).then((event) => {
result.toinvalidate.push({
event: event,
repeated: data.repeat ? event.eventcount : 1
});
}).catch(() => {
// Ignore errors.
}));
return Promise.all(promises); return Promise.all(promises);
}).catch((error) => { }).catch((error) => {
@ -257,6 +265,15 @@ export class AddonCalendarSyncProvider extends CoreSyncBaseProvider {
result.updated = true; result.updated = true;
result.events.push(newEvent); result.events.push(newEvent);
// Add data to invalidate.
const numberOfRepetitions = data.repeat ? data.repeats :
(data.repeateditall && newEvent.repeatid ? newEvent.eventcount : 1);
result.toinvalidate.push({
event: newEvent,
repeated: numberOfRepetitions
});
// Event sent, delete the offline data. // Event sent, delete the offline data.
return this.calendarOffline.deleteEvent(event.id, siteId); return this.calendarOffline.deleteEvent(event.id, siteId);
}).catch((error) => { }).catch((error) => {

View File

@ -344,73 +344,100 @@ export class AddonCalendarHelperProvider {
/** /**
* Invalidate all calls from calendar WS calls. * Invalidate all calls from calendar WS calls.
* *
* @param {any} event Event that has been touched. * @param {{event: any, repeated: number}[]} events Events that have been touched and number of times each event is repeated.
* @param {number} repeated Number of times the event is repeated.
* @param {string} [siteId] Site ID. If not defined, current site. * @param {string} [siteId] Site ID. If not defined, current site.
* @return {Promise<any>} REsolved when done. * @return {Promise<any>} Resolved when done.
*/ */
invalidateRepeatedEventsOnCalendar(event: any, repeated: number, siteId?: string): Promise<any> { invalidateRepeatedEventsOnCalendar(events: {event: any, repeated: number}[], siteId?: string): Promise<any> {
return this.sitesProvider.getSite(siteId).then((site) => { return this.sitesProvider.getSite(siteId).then((site) => {
let invalidatePromise;
const timestarts = []; const timestarts = [];
if (repeated > 1) { // Invalidate the events and get the timestarts so we can invalidate months & days.
if (event.repeatid) { return this.utils.allPromises(events.map((eventData) => {
// Being edited or deleted.
invalidatePromise = this.calendarProvider.getLocalEventsByRepeatIdFromLocalDb(event.repeatid, site.id)
.then((events) => {
return this.utils.allPromises(events.map((event) => {
timestarts.push(event.timestart);
return this.calendarProvider.invalidateEvent(event.id); if (eventData.repeated > 1) {
})); if (eventData.event.repeatid) {
}); // Being edited or deleted.
} else { // We need to calculate the days to invalidate because the event date could have changed.
// Being added. // We don't know if the repeated events are before or after this one, invalidate them all.
let time = event.timestart; timestarts.push(eventData.event.timestart);
while (repeated > 0) {
timestarts.push(time); for (let i = 1; i < eventData.repeated; i++) {
time += CoreConstants.SECONDS_DAY * 7; timestarts.push(eventData.event.timestart + CoreConstants.SECONDS_DAY * 7 * i);
repeated--; timestarts.push(eventData.event.timestart - CoreConstants.SECONDS_DAY * 7 * i);
}
// Get the repeated events to invalidate them.
return this.calendarProvider.getLocalEventsByRepeatIdFromLocalDb(eventData.event.repeatid, site.id)
.then((events) => {
return this.utils.allPromises(events.map((event) => {
return this.calendarProvider.invalidateEvent(event.id);
}));
});
} else {
// Being added.
let time = eventData.event.timestart;
while (eventData.repeated > 0) {
timestarts.push(time);
time += CoreConstants.SECONDS_DAY * 7;
eventData.repeated--;
}
return Promise.resolve();
} }
} else {
// Not repeated.
timestarts.push(eventData.event.timestart);
invalidatePromise = Promise.resolve(); return this.calendarProvider.invalidateEvent(eventData.event.id);
} }
} else {
// Not repeated.
timestarts.push(event.timestart);
invalidatePromise = this.calendarProvider.invalidateEvent(event.id);
}
return invalidatePromise.finally(() => { })).finally(() => {
let lastMonth, lastYear; const invalidatedMonths = {},
invalidatedDays = {};
return this.utils.allPromises([ return this.utils.allPromises([
this.calendarProvider.invalidateAllUpcomingEvents(), this.calendarProvider.invalidateAllUpcomingEvents(),
// Invalidate months. // Invalidate months and days.
this.utils.allPromises(timestarts.map((time) => { this.utils.allPromises(timestarts.map((time) => {
const day = moment(new Date(time * 1000)); const promises = [],
day = moment(new Date(time * 1000)),
monthId = this.getMonthId(day.year(), day.month() + 1),
dayId = monthId + '#' + day.date();
if (lastMonth && (lastMonth == day.month() + 1 && lastYear == day.year())) { if (!invalidatedMonths[monthId]) {
return Promise.resolve(); // Month not invalidated already, do it now.
invalidatedMonths[monthId] = monthId;
promises.push(this.calendarProvider.invalidateMonthlyEvents(day.year(), day.month() + 1, site.id));
} }
// Invalidate once. if (!invalidatedDays[dayId]) {
lastMonth = day.month() + 1; // Day not invalidated already, do it now.
lastYear = day.year(); invalidatedDays[dayId] = dayId;
return this.calendarProvider.invalidateMonthlyEvents(lastYear, lastMonth, site.id); promises.push(this.calendarProvider.invalidateDayEvents(day.year(), day.month() + 1, day.date(),
})), site.id));
}
// Invalidate days. return this.utils.allPromises(promises);
this.utils.allPromises(timestarts.map((time) => { }))
const day = moment(new Date(time * 1000));
return this.calendarProvider.invalidateDayEvents(day.year(), day.month() + 1, day.date(), site.id);
})),
]); ]);
}); });
}); });
} }
/**
* Invalidate all calls from calendar WS calls.
*
* @param {any} event Event that has been touched.
* @param {number} repeated Number of times the event is repeated.
* @param {string} [siteId] Site ID. If not defined, current site.
* @return {Promise<any>} Resolved when done.
*/
invalidateRepeatedEventsOnCalendarForEvent(event: any, repeated: number, siteId?: string): Promise<any> {
return this.invalidateRepeatedEventsOnCalendar([{event: event, repeated: repeated}], siteId);
}
} }