From c8bb1647c6e4886efb99fd69e7118815a0761e12 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pau=20Ferrer=20Oca=C3=B1a?= <crazyserver@gmail.com>
Date: Fri, 15 Feb 2019 14:16:24 +0100
Subject: [PATCH] MOBILE-2796 calendar: Fix default time issues

---
 scripts/langindex.json                    |  2 ++
 src/addon/calendar/pages/event/event.html | 32 ++++++++++--------
 src/addon/calendar/pages/event/event.ts   | 10 +++++-
 src/addon/calendar/providers/calendar.ts  | 41 ++++++++++++++---------
 src/addon/mod/data/providers/offline.ts   |  2 +-
 src/providers/sites.ts                    |  5 +--
 6 files changed, 58 insertions(+), 34 deletions(-)

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/pages/event/event.html b/src/addon/calendar/pages/event/event.html
index b69e67962..c00376085 100644
--- a/src/addon/calendar/pages/event/event.html
+++ b/src/addon/calendar/pages/event/event.html
@@ -56,21 +56,25 @@
             <ion-item>
                 <h2>{{ 'addon.calendar.reminders' | translate }}</h2>
             </ion-item>
-            <ion-item [class.item-dimmed]="(reminder.time == -1 ? (event.timestart - defaultTime) : reminder.time) <= currentTime" *ngFor="let reminder of reminders">
-                <p *ngIf="reminder.time == -1">{{ 'core.defaultvalue' | translate :{$a: ((event.timestart - defaultTime) * 1000) | coreFormatDate } }}</p>
-                <p *ngIf="reminder.time > 0">{{ reminder.time * 1000 | coreFormatDate }}</p>
-                <button ion-button icon-only clear="true" (click)="cancelNotification(reminder.id, $event)" [attr.aria-label]=" 'core.delete' | translate" item-end *ngIf="(reminder.time == -1 ? (event.timestart - defaultTime) : reminder.time) > currentTime">
-                    <ion-icon name="trash" color="danger"></ion-icon>
-                </button>
-            </ion-item>
+            <ng-container *ngFor="let reminder of reminders">
+                <ion-item  *ngIf="reminder.time > 0 || defaultTime > 0" [class.item-dimmed]="(reminder.time == -1 ? (event.timestart - defaultTime) : reminder.time) <= currentTime" >
+                    <p *ngIf="reminder.time == -1">{{ 'core.defaultvalue' | translate :{$a: ((event.timestart - defaultTime) * 1000) | coreFormatDate } }}</p>
+                    <p *ngIf="reminder.time > 0">{{ reminder.time * 1000 | coreFormatDate }}</p>
+                    <button ion-button icon-only clear="true" (click)="cancelNotification(reminder.id, $event)" [attr.aria-label]=" 'core.delete' | translate" item-end *ngIf="(reminder.time == -1 ? (event.timestart - defaultTime) : reminder.time) > currentTime">
+                        <ion-icon name="trash" color="danger"></ion-icon>
+                    </button>
+                </ion-item>
+            </ng-container>
 
-            <ion-item *ngIf="event.timestart + event.timeduration > currentTime">
-                <ion-label stacked>{{ 'addon.calendar.setnewreminder' | translate }}</ion-label>
-                <ion-datetime [(ngModel)]="notificationTimeText" [placeholder]="'core.choosedots' | translate" [displayFormat]="notificationFormat" [min]="notificationMin" [max]="notificationMax"></ion-datetime>
-            </ion-item>
-            <ion-item *ngIf="event.timestart + event.timeduration > currentTime">
-                <button ion-button block color="primary" (click)="addNotificationTime($event)" [disabled]="!notificationTimeText">{{ 'addon.calendar.setnewreminder' | translate }}</button>
-            </ion-item>
+            <ng-container *ngIf="event.timestart + event.timeduration > currentTime">
+                <ion-item>
+                    <ion-label stacked>{{ 'addon.calendar.setnewreminder' | translate }}</ion-label>
+                    <ion-datetime [(ngModel)]="notificationTimeText" [placeholder]="'core.choosedots' | translate" [displayFormat]="notificationFormat" [min]="notificationMin" [max]="notificationMax"></ion-datetime>
+                </ion-item>
+                <ion-item>
+                    <button ion-button block color="primary" (click)="addNotificationTime($event)" [disabled]="!notificationTimeText">{{ 'addon.calendar.setnewreminder' | translate }}</button>
+                </ion-item>
+            </ng-container>
         </ion-card>
     </core-loading>
 </ion-content>
diff --git a/src/addon/calendar/pages/event/event.ts b/src/addon/calendar/pages/event/event.ts
index dae20076d..568eac629 100644
--- a/src/addon/calendar/pages/event/event.ts
+++ b/src/addon/calendar/pages/event/event.ts
@@ -191,7 +191,15 @@ export class AddonCalendarEventPage {
         e.stopPropagation();
 
         if (this.notificationTimeText && this.event && this.event.id) {
-            const notificationTime = this.timeUtils.convertToTimestamp(this.notificationTimeText);
+            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) => {
diff --git a/src/addon/calendar/providers/calendar.ts b/src/addon/calendar/providers/calendar.ts
index 6d17d056a..14ad8d69b 100644
--- a/src/addon/calendar/providers/calendar.ts
+++ b/src/addon/calendar/providers/calendar.ts
@@ -38,7 +38,7 @@ export class AddonCalendarProvider {
     protected ROOT_CACHE_KEY = 'mmaCalendar:';
 
     // Variables for database.
-    static EVENTS_TABLE = 'addon_calendar_events_1';
+    static EVENTS_TABLE = 'addon_calendar_events_2';
     static REMINDERS_TABLE = 'addon_calendar_reminders';
     protected siteSchema: CoreSiteSchema = {
         name: 'AddonCalendarProvider',
@@ -149,7 +149,7 @@ export class AddonCalendarProvider {
                 ]
             }
         ],
-        migrate(db: SQLiteDB, oldVersion: number): Promise<any> | void {
+        migrate(db: SQLiteDB, oldVersion: number, siteId: string): Promise<any> | void {
             if (oldVersion < 2) {
                 const newTable = AddonCalendarProvider.EVENTS_TABLE;
                 const oldTable = 'addon_calendar_events';
@@ -182,6 +182,9 @@ export class AddonCalendarProvider {
                                 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.
@@ -371,20 +374,13 @@ export class AddonCalendarProvider {
      */
     addEventReminder(event: any, time: number, siteId?: string): Promise<any> {
         return this.sitesProvider.getSite(siteId).then((site) => {
-            siteId = site.getId();
-
-            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);
-            }
-
             const reminder = {
                 eventid: event.id,
                 time: time
             };
 
             return site.getDb().insertRecord(AddonCalendarProvider.REMINDERS_TABLE, reminder).then((reminderId) => {
-                return this.scheduleEventNotification(event, reminderId, time, siteId);
+                return this.scheduleEventNotification(event, reminderId, time, site.getId());
             });
         });
     }
@@ -623,12 +619,25 @@ export class AddonCalendarProvider {
                 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) => {
+                time = time * 1000;
 
-                if (time * 1000 <= new Date().getTime()) {
+                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);
                 }
@@ -638,7 +647,7 @@ export class AddonCalendarProvider {
                         title: event.name,
                         text: this.timeUtils.userDate(event.timestart * 1000, 'core.strftimedaydatetime', true),
                         trigger: {
-                            at: new Date(time * 1000)
+                            at: new Date(time)
                         },
                         data: {
                             eventid: event.id,
@@ -714,7 +723,7 @@ export class AddonCalendarProvider {
         return this.sitesProvider.getSite(siteId).then((site) => {
             siteId = site.getId();
 
-            // If event does not exists on the DB, schedule the reminder.
+            // 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) => {
@@ -762,7 +771,7 @@ export class AddonCalendarProvider {
             siteId = site.getId();
 
             return Promise.all(events.map((event) => {
-                // If event does not exists on the DB, schedule the reminder.
+                // 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<any> | void {
+        migrate(db: SQLiteDB, oldVersion: number, siteId: string): Promise<any> | void {
             if (oldVersion == 0) {
                 // Move the records from the old table.
                 const newTable = AddonModDataOfflineProvider.DATA_ENTRY_TABLE;
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<any> | void} Promise resolved when done.
      */
-    migrate?(db: SQLiteDB, oldVersion: number): Promise<any> | void;
+    migrate?(db: SQLiteDB, oldVersion: number, siteId: string): Promise<any> | 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.