diff --git a/scripts/langindex.json b/scripts/langindex.json index 3993e76f7..390e3fa12 100644 --- a/scripts/langindex.json +++ b/scripts/langindex.json @@ -66,6 +66,8 @@ "addon.calendar.gotoactivity": "calendar", "addon.calendar.noevents": "local_moodlemobileapp", "addon.calendar.notifications": "local_moodlemobileapp", + "addon.calendar.reminders": "local_moodlemobileapp", + "addon.calendar.setnewreminder": "local_moodlemobileapp", "addon.calendar.typecategory": "calendar", "addon.calendar.typeclose": "calendar", "addon.calendar.typecourse": "calendar", diff --git a/src/addon/calendar/calendar.module.ts b/src/addon/calendar/calendar.module.ts index 85aa71eb2..3146e6e69 100644 --- a/src/addon/calendar/calendar.module.ts +++ b/src/addon/calendar/calendar.module.ts @@ -71,7 +71,7 @@ export class AddonCalendarModule { newName: AddonCalendarProvider.EVENTS_TABLE, filterFields: ['id', 'name', 'description', 'format', 'eventtype', 'courseid', 'timestart', 'timeduration', 'categoryid', 'groupid', 'userid', 'instance', 'modulename', 'timemodified', 'repeatid', 'visible', 'uuid', - 'sequence', 'subscriptionid', 'notificationtime'] + 'sequence', 'subscriptionid'] }); // Migrate the component name. diff --git a/src/addon/calendar/lang/en.json b/src/addon/calendar/lang/en.json index 3342aaeeb..1fc6d2e34 100644 --- a/src/addon/calendar/lang/en.json +++ b/src/addon/calendar/lang/en.json @@ -8,7 +8,8 @@ "eventstarttime": "Start time", "gotoactivity": "Go to activity", "noevents": "There are no events", - "notifications": "Notifications", + "reminders": "Reminders", + "setnewreminder": "Set a new reminder", "typeclose": "Close event", "typecourse": "Course event", "typecategory": "Category event", diff --git a/src/addon/calendar/pages/event/event.html b/src/addon/calendar/pages/event/event.html index a9711f678..c00376085 100644 --- a/src/addon/calendar/pages/event/event.html +++ b/src/addon/calendar/pages/event/event.html @@ -10,10 +10,10 @@ - + - - +

+

{{ 'addon.calendar.eventstarttime' | translate}}

{{ event.timestart * 1000 | coreFormatDate }}

@@ -52,21 +52,29 @@
- + - {{ 'addon.calendar.notifications' | translate }} - - {{ 'core.defaultvalue' | translate :{$a: defaultTimeReadable} }} - {{ 'core.settings.disabled' | translate }} - {{ 600 | coreDuration }} - {{ 1800 | coreDuration }} - {{ 3600 | coreDuration }} - {{ 7200 | coreDuration }} - {{ 21600 | coreDuration }} - {{ 43200 | coreDuration }} - {{ 86400 | coreDuration }} - +

{{ 'addon.calendar.reminders' | translate }}

+ + +

{{ 'core.defaultvalue' | translate :{$a: ((event.timestart - defaultTime) * 1000) | coreFormatDate } }}

+

{{ reminder.time * 1000 | coreFormatDate }}

+ +
+
+ + + + {{ 'addon.calendar.setnewreminder' | translate }} + + + + + +
diff --git a/src/addon/calendar/pages/event/event.ts b/src/addon/calendar/pages/event/event.ts index e20a61877..568eac629 100644 --- a/src/addon/calendar/pages/event/event.ts +++ b/src/addon/calendar/pages/event/event.ts @@ -39,8 +39,10 @@ export class AddonCalendarEventPage { protected eventId; protected siteHomeId: number; eventLoaded: boolean; - notificationTime: number; - defaultTimeReadable: string; + notificationFormat: string; + notificationMin: string; + notificationMax: string; + notificationTimeText: string; event: any = {}; title: string; courseName: string; @@ -50,6 +52,7 @@ export class AddonCalendarEventPage { categoryPath = ''; currentTime: number; defaultTime: number; + reminders: any[]; constructor(private translate: TranslateService, private calendarProvider: AddonCalendarProvider, navParams: NavParams, private domUtils: CoreDomUtilsProvider, private coursesProvider: CoreCoursesProvider, @@ -61,21 +64,17 @@ export class AddonCalendarEventPage { this.notificationsEnabled = localNotificationsProvider.isAvailable(); this.siteHomeId = sitesProvider.getCurrentSite().getSiteHomeId(); if (this.notificationsEnabled) { - this.calendarProvider.getEventNotificationTimeOption(this.eventId).then((notificationTime) => { - this.notificationTime = notificationTime; - this.loadNotificationTime(); + this.calendarProvider.getEventReminders(this.eventId).then((reminders) => { + this.reminders = reminders; }); this.calendarProvider.getDefaultNotificationTime().then((defaultTime) => { this.defaultTime = defaultTime * 60; - this.loadNotificationTime(); - if (defaultTime === 0) { - // Disabled by default. - this.defaultTimeReadable = this.translate.instant('core.settings.disabled'); - } else { - this.defaultTimeReadable = timeUtils.formatTime(defaultTime * 60); - } }); + + // Calculate format to use. ion-datetime doesn't support escaping characters ([]), so we remove them. + this.notificationFormat = this.timeUtils.convertPHPToMoment(this.translate.instant('core.strftimedatetimeshort')) + .replace(/[\[\]]/g, ''); } } @@ -88,12 +87,6 @@ export class AddonCalendarEventPage { }); } - updateNotificationTime(): void { - if (!isNaN(this.notificationTime) && this.event && this.event.id) { - this.calendarProvider.updateNotificationTime(this.event, this.notificationTime); - } - } - /** * Fetches the event and updates the view. * @@ -117,7 +110,9 @@ export class AddonCalendarEventPage { this.event = event; this.currentTime = this.timeUtils.timestamp(); - this.loadNotificationTime(); + this.notificationMin = this.timeUtils.userDate(this.currentTime * 1000, 'YYYY-MM-DDTHH:mm', false); + this.notificationMax = this.timeUtils.userDate((event.timestart + event.timeduration) * 1000, + 'YYYY-MM-DDTHH:mm', false); // Reset some of the calculated data. this.categoryPath = ''; @@ -187,18 +182,52 @@ export class AddonCalendarEventPage { } /** - * Loads notification time by discarding options not in the list. + * Add a reminder for this event. + * + * @param {Event} e Click event. */ - loadNotificationTime(): void { - if (typeof this.notificationTime != 'undefined') { - if (this.notificationTime > 0 && this.event.timestart - this.notificationTime * 60 < this.currentTime) { - this.notificationTime = 0; - } else if (this.notificationTime < 0 && this.event.timestart - this.defaultTime < this.currentTime) { - this.notificationTime = 0; + addNotificationTime(e: Event): void { + e.preventDefault(); + e.stopPropagation(); + + if (this.notificationTimeText && this.event && this.event.id) { + let notificationTime = this.timeUtils.convertToTimestamp(this.notificationTimeText); + + const currentTime = this.timeUtils.timestamp(), + minute = Math.floor(currentTime / 60) * 60; + + // Check if the notification time is in the same minute as we are, so the notification is triggered. + if (notificationTime >= minute && notificationTime < minute + 60) { + notificationTime = currentTime + 1; } + + this.calendarProvider.addEventReminder(this.event, notificationTime).then(() => { + this.calendarProvider.getEventReminders(this.eventId).then((reminders) => { + this.reminders = reminders; + }); + + this.notificationTimeText = null; + }); } } + /** + * Cancel the selected notification. + * + * @param {number} id Reminder ID. + * @param {Event} e Click event. + */ + cancelNotification(id: number, e: Event): void { + e.preventDefault(); + e.stopPropagation(); + + this.calendarProvider.deleteEventReminder(id).then(() => { + this.calendarProvider.getEventReminders(this.eventId).then((reminders) => { + this.reminders = reminders; + }); + }); + } + /** * Refresh the event. * diff --git a/src/addon/calendar/providers/calendar.ts b/src/addon/calendar/providers/calendar.ts index ab5b3e301..14ad8d69b 100644 --- a/src/addon/calendar/providers/calendar.ts +++ b/src/addon/calendar/providers/calendar.ts @@ -23,6 +23,7 @@ import { CoreConstants } from '@core/constants'; import { CoreLocalNotificationsProvider } from '@providers/local-notifications'; import { CoreConfigProvider } from '@providers/config'; import { ILocalNotification } from '@ionic-native/local-notifications'; +import { SQLiteDB } from '@classes/sqlitedb'; /** * Service to handle calendar events. @@ -37,10 +38,11 @@ export class AddonCalendarProvider { protected ROOT_CACHE_KEY = 'mmaCalendar:'; // Variables for database. - static EVENTS_TABLE = 'addon_calendar_events'; + static EVENTS_TABLE = 'addon_calendar_events_2'; + static REMINDERS_TABLE = 'addon_calendar_reminders'; protected siteSchema: CoreSiteSchema = { name: 'AddonCalendarProvider', - version: 1, + version: 2, tables: [ { name: AddonCalendarProvider.EVENTS_TABLE, @@ -50,10 +52,6 @@ export class AddonCalendarProvider { type: 'INTEGER', primaryKey: true }, - { - name: 'notificationtime', - type: 'INTEGER' - }, { name: 'name', type: 'TEXT', @@ -128,8 +126,80 @@ export class AddonCalendarProvider { type: 'INTEGER' } ] + }, + { + name: AddonCalendarProvider.REMINDERS_TABLE, + columns: [ + { + name: 'id', + type: 'INTEGER', + primaryKey: true + }, + { + name: 'eventid', + type: 'INTEGER' + }, + { + name: 'time', + type: 'INTEGER' + } + ], + uniqueKeys: [ + ['eventid', 'time'] + ] } - ] + ], + migrate(db: SQLiteDB, oldVersion: number, siteId: string): Promise | void { + if (oldVersion < 2) { + const newTable = AddonCalendarProvider.EVENTS_TABLE; + const oldTable = 'addon_calendar_events'; + + return db.tableExists(oldTable).then(() => { + return db.getAllRecords(oldTable).then((events) => { + const now = Math.round(Date.now() / 1000); + + return Promise.all(events.map((event) => { + if (event.notificationtime == 0) { + // No reminders. + return Promise.resolve(); + } + + let time; + + if (event.notificationtime == -1) { + time = -1; + } else { + time = event.timestart - event.notificationtime * 60; + + if (time < now) { + // Old reminder, just not add this. + return Promise.resolve(); + } + } + + const reminder = { + eventid: event.id, + time: time + }; + + // Cancel old notification. + this.localNotificationsProvider.cancel(event.id, AddonCalendarProvider.COMPONENT, siteId); + + return db.insertRecord(AddonCalendarProvider.REMINDERS_TABLE, reminder); + })).then(() => { + // Move the records from the old table. + return db.insertRecordsFrom(newTable, oldTable, undefined, 'id, name, description, format, eventtype,\ + courseid, timestart, timeduration, categoryid, groupid, userid, instance, modulename, timemodified,\ + repeatid, visible, uuid, sequence, subscriptionid'); + }).then(() => { + return db.dropTable(oldTable); + }); + }); + }).catch(() => { + // Old table does not exist, ignore. + }); + } + } }; protected logger; @@ -145,29 +215,42 @@ export class AddonCalendarProvider { * Removes expired events from local DB. * * @param {string} [siteId] ID of the site the event belongs to. If not defined, use current site. - * @return {Promise} Promise resolved when done. + * @return {Promise} Promise resolved when done. */ - cleanExpiredEvents(siteId?: string): Promise { + cleanExpiredEvents(siteId?: string): Promise { return this.sitesProvider.getSite(siteId).then((site) => { - let promise; + return site.getDb().getRecordsSelect(AddonCalendarProvider.EVENTS_TABLE, 'timestart + timeduration < ?', + [this.timeUtils.timestamp()]).then((events) => { + return Promise.all(events.map((event) => { + return this.deleteEvent(event.id, siteId); + })); + }); + }); + } - // Cancel expired events notifications first. - if (this.localNotificationsProvider.isAvailable()) { - promise = site.getDb().getRecordsSelect(AddonCalendarProvider.EVENTS_TABLE, 'timestart < ?', - [this.timeUtils.timestamp()]).then((events) => { - events.forEach((event) => { - return this.localNotificationsProvider.cancel(event.id, AddonCalendarProvider.COMPONENT, site.getId()); - }); - }).catch(() => { - // Ignore errors. - }); - } else { - promise = Promise.resolve(); - } + /** + * Delete event cancelling all the reminders and notifications. + * + * @param {number} eventId Event ID. + * @param {string} [siteId] ID of the site the event belongs to. If not defined, use current site. + * @return {Promise} Resolved when done. + */ + protected deleteEvent(eventId: number, siteId?: string): Promise { + return this.sitesProvider.getSite(siteId).then((site) => { + siteId = site.getId(); - return promise.then(() => { - return site.getDb().deleteRecordsSelect(AddonCalendarProvider.EVENTS_TABLE, 'timestart < ?', - [this.timeUtils.timestamp()]); + const promises = []; + + promises.push(site.getDb().deleteRecords(AddonCalendarProvider.EVENTS_TABLE, {id: eventId})); + + promises.push(site.getDb().getRecords(AddonCalendarProvider.REMINDERS_TABLE, {eventid: eventId}).then((reminders) => { + return Promise.all(reminders.map((reminder) => { + return this.deleteEventReminder(reminder.id, siteId); + })); + })); + + return Promise.all(promises).catch(() => { + // Ignore errors. }); }); } @@ -282,36 +365,53 @@ export class AddonCalendarProvider { } /** - * Get event notification time. Always returns number of minutes (0 if disabled). + * Adds an event reminder and schedule a new notification. * - * @param {number} id Event ID. + * @param {any} event Event to update its notification time. + * @param {number} time New notification setting timestamp. * @param {string} [siteId] ID of the site the event belongs to. If not defined, use current site. - * @return {Promise} Event notification time in minutes. 0 if disabled. + * @return {Promise} Promise resolved when the notification is updated. */ - getEventNotificationTime(id: number, siteId?: string): Promise { - siteId = siteId || this.sitesProvider.getCurrentSiteId(); + addEventReminder(event: any, time: number, siteId?: string): Promise { + return this.sitesProvider.getSite(siteId).then((site) => { + const reminder = { + eventid: event.id, + time: time + }; - return this.getEventNotificationTimeOption(id, siteId).then((time: number) => { - if (time == -1) { - return this.getDefaultNotificationTime(siteId); - } - - return time; + return site.getDb().insertRecord(AddonCalendarProvider.REMINDERS_TABLE, reminder).then((reminderId) => { + return this.scheduleEventNotification(event, reminderId, time, site.getId()); + }); }); } /** - * Get event notification time for options. Returns -1 for default time. + * Remove an event reminder and cancel the notification. + * + * @param {number} id Reminder ID. + * @param {string} [siteId] ID of the site the event belongs to. If not defined, use current site. + * @return {Promise} Promise resolved when the notification is updated. + */ + deleteEventReminder(id: number, siteId?: string): Promise { + return this.sitesProvider.getSite(siteId).then((site) => { + if (this.localNotificationsProvider.isAvailable()) { + this.localNotificationsProvider.cancel(id, AddonCalendarProvider.COMPONENT, site.getId()); + } + + return site.getDb().deleteRecords(AddonCalendarProvider.REMINDERS_TABLE, {id: id}); + }); + } + + /** + * Get a calendar reminders from local Db. * * @param {number} id Event ID. * @param {string} [siteId] ID of the site the event belongs to. If not defined, use current site. - * @return {Promise} Promise with wvent notification time in minutes. 0 if disabled, -1 if default time. + * @return {Promise} Promise resolved when the event data is retrieved. */ - getEventNotificationTimeOption(id: number, siteId?: string): Promise { - return this.getEventFromLocalDb(id, siteId).then((e) => { - return e.notificationtime || -1; - }).catch(() => { - return -1; + getEventReminders(id: number, siteId?: string): Promise { + return this.sitesProvider.getSite(siteId).then((site) => { + return site.getDb().getRecords(AddonCalendarProvider.REMINDERS_TABLE, {eventid: id}, 'time ASC'); }); } @@ -510,34 +610,48 @@ export class AddonCalendarProvider { * @param {string} [siteId] Site ID the event belongs to. If not defined, use current site. * @return {Promise} Promise resolved when the notification is scheduled. */ - scheduleEventNotification(event: any, time: number, siteId?: string): Promise { + protected scheduleEventNotification(event: any, reminderId: number, time: number, siteId?: string): Promise { if (this.localNotificationsProvider.isAvailable()) { siteId = siteId || this.sitesProvider.getCurrentSiteId(); if (time === 0) { // Cancel if it was scheduled. - return this.localNotificationsProvider.cancel(event.id, AddonCalendarProvider.COMPONENT, siteId); + return this.localNotificationsProvider.cancel(reminderId, AddonCalendarProvider.COMPONENT, siteId); } - // If time is -1, get event default time. - const promise = time == -1 ? this.getDefaultNotificationTime(siteId) : Promise.resolve(time); + let promise; + if (time == -1) { + // If time is -1, get event default time to calculate the notification time. + promise = this.getDefaultNotificationTime(siteId).then((time) => { + if (time == 0) { + // Default notification time is disabled, do not show. + return this.localNotificationsProvider.cancel(reminderId, AddonCalendarProvider.COMPONENT, siteId); + } + + return event.timestart - (time * 60); + }); + } else { + promise = Promise.resolve(time); + } return promise.then((time) => { - const timeEnd = (event.timestart + event.timeduration) * 1000; - if (timeEnd <= new Date().getTime()) { - // The event has finished already, don't schedule it. - return Promise.resolve(); + time = time * 1000; + + if (time <= new Date().getTime()) { + // This reminder is over, don't schedule. Cancel if it was scheduled. + return this.localNotificationsProvider.cancel(reminderId, AddonCalendarProvider.COMPONENT, siteId); } const notification: ILocalNotification = { - id: event.id, + id: reminderId, title: event.name, text: this.timeUtils.userDate(event.timestart * 1000, 'core.strftimedaydatetime', true), trigger: { - at: new Date((event.timestart - (time * 60)) * 1000) + at: new Date(time) }, data: { eventid: event.id, + reminderid: reminderId, siteid: siteId } }; @@ -560,18 +674,27 @@ export class AddonCalendarProvider { * @return {Promise} Promise resolved when all the notifications have been scheduled. */ scheduleEventsNotifications(events: any[], siteId?: string): Promise { - const promises = []; if (this.localNotificationsProvider.isAvailable()) { siteId = siteId || this.sitesProvider.getCurrentSiteId(); - events.forEach((e) => { - promises.push(this.getEventNotificationTime(e.id, siteId).then((time) => { - return this.scheduleEventNotification(e, time, siteId); - })); - }); + + return Promise.all(events.map((event) => { + const timeEnd = (event.timestart + event.timeduration) * 1000; + + if (timeEnd <= new Date().getTime()) { + // The event has finished already, don't schedule it. + return this.deleteEvent(event.id, siteId); + } + + return this.getEventReminders(event.id, siteId).then((reminders) => { + return Promise.all(reminders.map((reminder) => { + return this.scheduleEventNotification(event, reminder.id, reminder.time, siteId); + })); + }); + })); } - return Promise.all(promises); + return Promise.resolve([]); } /** @@ -598,7 +721,41 @@ export class AddonCalendarProvider { */ storeEventInLocalDb(event: any, siteId?: string): Promise { return this.sitesProvider.getSite(siteId).then((site) => { - return site.getDb().insertRecord(AddonCalendarProvider.EVENTS_TABLE, event); + siteId = site.getId(); + + // If event does not exist on the DB, schedule the reminder. + return this.getEventFromLocalDb(event.id, site.id).catch(() => { + // Event does not exist. Check if any reminder exists first. + return this.getEventReminders(event.id, siteId).then((reminders) => { + if (reminders.length == 0) { + this.addEventReminder(event, -1, siteId); + } + }); + }).then(() => { + const eventRecord = { + id: event.id, + name: event.name, + description: event.description, + format: event.format, + eventtype: event.eventtype, + courseid: event.courseid, + timestart: event.timestart, + timeduration: event.timeduration, + categoryid: event.categoryid, + groupid: event.groupid, + userid: event.userid, + instance: event.instance, + modulename: event.modulename, + timemodified: event.timemodified, + repeatid: event.repeatid, + visible: event.visible, + uuid: event.uuid, + sequence: event.sequence, + subscriptionid: event.subscriptionid + }; + + return site.getDb().insertRecord(AddonCalendarProvider.EVENTS_TABLE, eventRecord); + }); }); } @@ -613,65 +770,10 @@ export class AddonCalendarProvider { return this.sitesProvider.getSite(siteId).then((site) => { siteId = site.getId(); - const promises = [], - db = site.getDb(); - - events.forEach((event) => { - // Don't override event notification time if the user configured it. - promises.push(this.getEventFromLocalDb(event.id, siteId).catch(() => { - // Event not stored, return empty object. - return {}; - }).then((e) => { - const eventRecord = { - id: event.id, - name: event.name, - description: event.description, - format: event.format, - eventtype: event.eventtype, - courseid: event.courseid, - timestart: event.timestart, - timeduration: event.timeduration, - categoryid: event.categoryid, - groupid: event.groupid, - userid: event.userid, - instance: event.instance, - modulename: event.modulename, - timemodified: event.timemodified, - repeatid: event.repeatid, - visible: event.visible, - uuid: event.uuid, - sequence: event.sequence, - subscriptionid: event.subscriptionid, - notificationtime: e.notificationtime || -1 - }; - - return db.insertRecord(AddonCalendarProvider.EVENTS_TABLE, eventRecord); - })); - }); - - return Promise.all(promises); - }); - } - - /** - * Updates an event notification time and schedule a new notification. - * - * @param {any} event Event to update its notification time. - * @param {number} time New notification setting time (in minutes). E.g. 10 means "notificate 10 minutes before start". - * @param {string} [siteId] ID of the site the event belongs to. If not defined, use current site. - * @return {Promise} Promise resolved when the notification is updated. - */ - updateNotificationTime(event: any, time: number, siteId?: string): Promise { - return this.sitesProvider.getSite(siteId).then((site) => { - if (!this.sitesProvider.isLoggedIn()) { - // Not logged in, we can't get the site DB. User logged out or session expired while an operation was ongoing. - return Promise.reject(null); - } - - return site.getDb().updateRecords(AddonCalendarProvider.EVENTS_TABLE, {notificationtime: time}, {id: event.id}) - .then(() => { - return this.scheduleEventNotification(event, time); - }); + return Promise.all(events.map((event) => { + // If event does not exist on the DB, schedule the reminder. + return this.storeEventInLocalDb(event, siteId); + })); }); } } diff --git a/src/addon/mod/data/providers/offline.ts b/src/addon/mod/data/providers/offline.ts index c9ed26257..0c773f978 100644 --- a/src/addon/mod/data/providers/offline.ts +++ b/src/addon/mod/data/providers/offline.ts @@ -69,7 +69,7 @@ export class AddonModDataOfflineProvider { primaryKeys: ['dataid', 'entryid', 'action'] } ], - migrate(db: SQLiteDB, oldVersion: number): Promise | void { + migrate(db: SQLiteDB, oldVersion: number, siteId: string): Promise | void { if (oldVersion == 0) { // Move the records from the old table. const newTable = AddonModDataOfflineProvider.DATA_ENTRY_TABLE; diff --git a/src/assets/lang/en.json b/src/assets/lang/en.json index 048521fcd..f440f6e3a 100644 --- a/src/assets/lang/en.json +++ b/src/assets/lang/en.json @@ -65,7 +65,8 @@ "addon.calendar.eventstarttime": "Start time", "addon.calendar.gotoactivity": "Go to activity", "addon.calendar.noevents": "There are no events", - "addon.calendar.notifications": "Notifications", + "addon.calendar.reminders": "Reminders", + "addon.calendar.setnewreminder": "Set a new reminder", "addon.calendar.typecategory": "Category event", "addon.calendar.typeclose": "Close event", "addon.calendar.typecourse": "Course event", diff --git a/src/providers/sites.ts b/src/providers/sites.ts index 7398ffcbe..759b89372 100644 --- a/src/providers/sites.ts +++ b/src/providers/sites.ts @@ -157,9 +157,10 @@ export interface CoreSiteSchema { * * @param {SQLiteDB} db Site database. * @param {number} oldVersion Old version of the schema or 0 if not installed. + * @param {string} siteId Site Id to migrate. * @return {Promise | void} Promise resolved when done. */ - migrate?(db: SQLiteDB, oldVersion: number): Promise | void; + migrate?(db: SQLiteDB, oldVersion: number, siteId: string): Promise | void; } /* @@ -1444,7 +1445,7 @@ export class CoreSitesProvider { promise = promise.then(() => db.createTablesFromSchema(schema.tables)); } if (schema.migrate) { - promise = promise.then(() => schema.migrate(db, oldVersion)); + promise = promise.then(() => schema.migrate(db, oldVersion, site.id)); } // Set installed version. diff --git a/src/providers/update-manager.ts b/src/providers/update-manager.ts index b4017eb1f..37ed1c0e8 100644 --- a/src/providers/update-manager.ts +++ b/src/providers/update-manager.ts @@ -21,6 +21,7 @@ import { CoreLocalNotificationsProvider } from './local-notifications'; import { CoreLoggerProvider } from './logger'; import { CoreSitesProvider } from './sites'; import { CoreUtilsProvider } from './utils/utils'; +import { CoreTimeUtilsProvider } from './utils/time'; import { CoreConfigConstants } from '../configconstants'; import { AddonCalendarProvider } from '@addon/calendar/providers/calendar'; import { SQLiteDB } from '@classes/sqlitedb'; @@ -321,7 +322,7 @@ export class CoreUpdateManagerProvider implements CoreInitHandler { constructor(logger: CoreLoggerProvider, private configProvider: CoreConfigProvider, private sitesProvider: CoreSitesProvider, private filepoolProvider: CoreFilepoolProvider, private notifProvider: CoreLocalNotificationsProvider, - private utils: CoreUtilsProvider, private appProvider: CoreAppProvider, + private utils: CoreUtilsProvider, private appProvider: CoreAppProvider, private timeUtils: CoreTimeUtilsProvider, private calendarProvider: AddonCalendarProvider) { this.logger = logger.getInstance('CoreUpdateManagerProvider'); } @@ -606,6 +607,8 @@ export class CoreUpdateManagerProvider implements CoreInitHandler { return Promise.resolve(); } + const now = this.timeUtils.timestamp(); + return this.sitesProvider.getSitesIds().then((siteIds) => { const promises = []; @@ -615,9 +618,16 @@ export class CoreUpdateManagerProvider implements CoreInitHandler { const eventPromises = []; events.forEach((event) => { - if (event.notificationtime == AddonCalendarProvider.DEFAULT_NOTIFICATION_TIME) { - event.notificationtime = -1; - eventPromises.push(this.calendarProvider.storeEventInLocalDb(event, siteId)); + if (event.notificationtime && event.notificationtime == AddonCalendarProvider.DEFAULT_NOTIFICATION_TIME) { + eventPromises.push(this.calendarProvider.addEventReminder(event, -1, siteId)); + } else if (event.notificationtime && event.notificationtime > 0) { + const time = event.timestart - event.notificationtime * 60; + + if (time < now) { + // Old reminder, just not add this. + return; + } + eventPromises.push(this.calendarProvider.addEventReminder(event, time, siteId)); } }); diff --git a/src/providers/utils/time.ts b/src/providers/utils/time.ts index 00bb2360b..e0c5633e1 100644 --- a/src/providers/utils/time.ts +++ b/src/providers/utils/time.ts @@ -276,6 +276,16 @@ export class CoreTimeUtilsProvider { return moment(timestamp).format(format); } + /** + * Convert a text into user timezone timestamp. + * + * @param {number} date To convert to timestamp. + * @return {number} Converted timestamp. + */ + convertToTimestamp(date: string): number { + return moment(date).unix() - (moment().utcOffset() * 60); + } + /** * Return the localized ISO format (i.e DDMMYY) from the localized moment format. Useful for translations. * DO NOT USE this function for ion-datetime format. Moment escapes characters with [], but ion-datetime doesn't support it.