forked from EVOgeek/Vmeda.Online
		
	
						commit
						6c518d55fa
					
				| @ -11,49 +11,52 @@ | ||||
|     </ion-toolbar> | ||||
| </ion-header> | ||||
| <ion-content> | ||||
|     <ion-radio-group [(ngModel)]="radioValue" class="ion-text-wrap"> | ||||
|         <!-- Preset options. --> | ||||
|         <ion-item *ngIf="allowDisable"> | ||||
|             <ion-label> | ||||
|                 <p>{{ 'core.settings.disabled' | translate }}</p> | ||||
|             </ion-label> | ||||
|             <ion-radio slot="end" value="disabled"></ion-radio> | ||||
|         </ion-item> | ||||
|         <ion-item *ngFor="let option of presetOptions"> | ||||
|             <ion-label> | ||||
|                 <p>{{ option.label }}</p> | ||||
|             </ion-label> | ||||
|             <ion-radio slot="end" [value]="option.radioValue"></ion-radio> | ||||
|         </ion-item> | ||||
|     <form (ngSubmit)="saveReminder()"> | ||||
|         <ion-radio-group name="radiovalue" [(ngModel)]="radioValue" class="ion-text-wrap"> | ||||
|             <!-- Preset options. --> | ||||
|             <ion-item *ngIf="allowDisable"> | ||||
|                 <ion-label> | ||||
|                     <p>{{ 'core.settings.disabled' | translate }}</p> | ||||
|                 </ion-label> | ||||
|                 <ion-radio slot="end" value="disabled"></ion-radio> | ||||
|             </ion-item> | ||||
|             <ion-item *ngFor="let option of presetOptions"> | ||||
|                 <ion-label> | ||||
|                     <p>{{ option.label }}</p> | ||||
|                 </ion-label> | ||||
|                 <ion-radio slot="end" [value]="option.radioValue"></ion-radio> | ||||
|             </ion-item> | ||||
| 
 | ||||
|         <!-- Custom value. --> | ||||
|         <ion-item class="ion-text-wrap"> | ||||
|             <ion-label> | ||||
|                 <p>{{ 'core.custom' | translate }}</p> | ||||
|             </ion-label> | ||||
|             <ion-radio slot="end" value="custom"></ion-radio> | ||||
|         </ion-item> | ||||
|         <ion-item class="ion-text-wrap"> | ||||
|             <ion-label></ion-label> | ||||
|             <!-- Custom value. --> | ||||
|             <ion-item class="ion-text-wrap"> | ||||
|                 <ion-label> | ||||
|                     <p>{{ 'core.custom' | translate }}</p> | ||||
|                 </ion-label> | ||||
|                 <ion-radio slot="end" value="custom"></ion-radio> | ||||
|             </ion-item> | ||||
|             <ion-item class="ion-text-wrap"> | ||||
|                 <ion-label></ion-label> | ||||
| 
 | ||||
|             <div class="flex-row"> | ||||
|                 <!-- Input to enter the value. --> | ||||
|                 <ion-input type="number" name="customvalue" [(ngModel)]="customValue" [disabled]="radioValue != 'custom'" placeholder="10"> | ||||
|                 </ion-input> | ||||
|                 <div class="flex-row"> | ||||
|                     <!-- Input to enter the value. --> | ||||
|                     <ion-input type="number" name="customvalue" [(ngModel)]="customValue" [disabled]="radioValue != 'custom'" | ||||
|                         placeholder="10" (click)="customInputClicked($event)"> | ||||
|                     </ion-input> | ||||
| 
 | ||||
|                 <!-- Units. --> | ||||
|                 <label class="accesshide" for="reminderUnits">{{ 'addon.calendar.units' | translate }}</label> | ||||
|                 <ion-select id="reminderUnits" name="customunits" [(ngModel)]="customUnits" interface="action-sheet" | ||||
|                     [disabled]="radioValue != 'custom'" slot="end" [interfaceOptions]="{header: 'addon.calendar.units' | translate}"> | ||||
|                     <ion-select-option *ngFor="let option of customUnitsOptions" [value]="option.value"> | ||||
|                         {{ option.label | translate }} | ||||
|                     </ion-select-option> | ||||
|                 </ion-select> | ||||
|             </div> | ||||
|         </ion-item> | ||||
|     </ion-radio-group> | ||||
|                     <!-- Units. --> | ||||
|                     <label class="accesshide" for="reminderUnits">{{ 'addon.calendar.units' | translate }}</label> | ||||
|                     <ion-select id="reminderUnits" name="customunits" [(ngModel)]="customUnits" interface="action-sheet" | ||||
|                         [disabled]="radioValue != 'custom'" slot="end" [interfaceOptions]="{header: 'addon.calendar.units' | translate}"> | ||||
|                         <ion-select-option *ngFor="let option of customUnitsOptions" [value]="option.value"> | ||||
|                             {{ option.label | translate }} | ||||
|                         </ion-select-option> | ||||
|                     </ion-select> | ||||
|                 </div> | ||||
|             </ion-item> | ||||
|         </ion-radio-group> | ||||
| 
 | ||||
|     <ion-button class="ion-margin" expand="block" (click)="saveReminder()" [disabled]="radioValue == 'custom' && !customValue"> | ||||
|         {{ 'core.done' | translate }} | ||||
|     </ion-button> | ||||
|         <ion-button type="submit" class="ion-margin" expand="block" [disabled]="radioValue == 'custom' && !customValue"> | ||||
|             {{ 'core.done' | translate }} | ||||
|         </ion-button> | ||||
|     </form> | ||||
| </ion-content> | ||||
|  | ||||
| @ -15,6 +15,7 @@ | ||||
| import { AddonCalendar, AddonCalendarReminderUnits, AddonCalendarValueAndUnit } from '@addons/calendar/services/calendar'; | ||||
| import { Component, Input, OnInit } from '@angular/core'; | ||||
| import { CoreDomUtils } from '@services/utils/dom'; | ||||
| import { CoreUtils } from '@services/utils/utils'; | ||||
| import { ModalController } from '@singletons'; | ||||
| 
 | ||||
| /** | ||||
| @ -153,4 +154,24 @@ export class AddonCalendarReminderTimeModalComponent implements OnInit { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Custom value input clicked. | ||||
|      * | ||||
|      * @param ev Click event. | ||||
|      */ | ||||
|     async customInputClicked(ev: Event): Promise<void> { | ||||
|         if (this.radioValue === 'custom') { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         this.radioValue = 'custom'; | ||||
| 
 | ||||
|         await CoreUtils.nextTick(); | ||||
| 
 | ||||
|         const target = <HTMLInputElement | Element | null> ev.target; | ||||
|         if (target && 'focus' in target) { | ||||
|             target.focus(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  | ||||
| @ -374,7 +374,9 @@ export class AddonCalendarDayPage implements OnInit, OnDestroy { | ||||
| 
 | ||||
|             const selectedDay = this.manager?.getSelectedItem(); | ||||
|             if (selectedDay) { | ||||
|                 params.timestamp = selectedDay.moment.unix() * 1000; | ||||
|                 // Use current time but in the specified day.
 | ||||
|                 const now = moment(); | ||||
|                 params.timestamp = selectedDay.moment.clone().set({ hour: now.hour(), minute: now.minute() }).unix() * 1000; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|  | ||||
| @ -520,7 +520,7 @@ export class AddonCalendarEditEventPage implements OnInit, OnDestroy, CanLeave { | ||||
| 
 | ||||
|         try { | ||||
|             const result = await AddonCalendar.submitEvent(this.eventId, data, { | ||||
|                 reminders: this.reminders, | ||||
|                 reminders: this.eventId ? [] : this.reminders, // Only allow adding reminders for new events.
 | ||||
|             }); | ||||
|             event = result.event; | ||||
| 
 | ||||
| @ -638,7 +638,8 @@ export class AddonCalendarEditEventPage implements OnInit, OnDestroy, CanLeave { | ||||
|      * @return Promise resolved when done. | ||||
|      */ | ||||
|     protected async initReminders(): Promise<void> { | ||||
|         if (!this.notificationsEnabled) { | ||||
|         // Don't init reminders when editing an event. Right now, only allow adding reminders for new events.
 | ||||
|         if (!this.notificationsEnabled || this.eventId) { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|  | ||||
| @ -136,7 +136,8 @@ | ||||
|             <ng-container *ngFor="let reminder of reminders"> | ||||
|                 <ion-item *ngIf="reminder.timestamp > 0" class="ion-text-wrap" [class.item-dimmed]="reminder.timestamp <= currentTime"> | ||||
|                     <ion-label> | ||||
|                         <p>{{ reminder.label }}</p> | ||||
|                         <p class="item-heading">{{ reminder.label }}</p> | ||||
|                         <p *ngIf="reminder.sublabel">{{ reminder.sublabel }}</p> | ||||
|                     </ion-label> | ||||
|                     <ion-button fill="clear" (click)="cancelNotification(reminder.id, $event)" [attr.aria-label]="'core.delete' | translate" | ||||
|                         slot="end"> | ||||
|  | ||||
| @ -37,6 +37,7 @@ import { AddonCalendarSyncInvalidateEvent } from './calendar-sync'; | ||||
| import { AddonCalendarOfflineEventDBRecord } from './database/calendar-offline'; | ||||
| import { CoreCategoryData } from '@features/courses/services/courses'; | ||||
| import { AddonCalendarReminderDBRecord } from './database/calendar'; | ||||
| import { CoreTimeUtils } from '@services/utils/time'; | ||||
| 
 | ||||
| /** | ||||
|  * Context levels enumeration. | ||||
| @ -329,6 +330,9 @@ export class AddonCalendarHelperProvider { | ||||
| 
 | ||||
|             if (reminder.value && reminder.unit) { | ||||
|                 reminder.label = AddonCalendar.getUnitValueLabel(reminder.value, reminder.unit, reminder.time === null); | ||||
|                 if (reminder.timestamp) { | ||||
|                     reminder.sublabel = CoreTimeUtils.userDate(reminder.timestamp * 1000, 'core.strftimedatetime'); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             return reminder; | ||||
| @ -796,4 +800,5 @@ export type AddonCalendarEventReminder = AddonCalendarReminderDBRecord & { | ||||
|     unit?: AddonCalendarReminderUnits; // Units.
 | ||||
|     timestamp?: number; // Timestamp (in seconds).
 | ||||
|     label?: string; // Label to represent the reminder.
 | ||||
|     sublabel?: string; // Sub label.
 | ||||
| }; | ||||
|  | ||||
| @ -777,6 +777,7 @@ export class AddonCalendarProvider { | ||||
|         const reminder: Partial<AddonCalendarReminderDBRecord> = { | ||||
|             eventid: event.id, | ||||
|             time: time ?? null, | ||||
|             timecreated: Date.now(), | ||||
|         }; | ||||
| 
 | ||||
|         const reminderId = await site.getDb().insertRecord(REMINDERS_TABLE, reminder); | ||||
| @ -913,7 +914,7 @@ export class AddonCalendarProvider { | ||||
|     async getEventReminders(id: number, siteId?: string): Promise<AddonCalendarReminderDBRecord[]> { | ||||
|         const site = await CoreSites.getSite(siteId); | ||||
| 
 | ||||
|         return await site.getDb().getRecords(REMINDERS_TABLE, { eventid: id }, 'time ASC'); | ||||
|         return await site.getDb().getRecords(REMINDERS_TABLE, { eventid: id }, 'timecreated ASC, time ASC'); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
| @ -1696,7 +1697,7 @@ export class AddonCalendarProvider { | ||||
|             const event = await AddonCalendarOffline.saveEvent(eventId, formData, siteId); | ||||
| 
 | ||||
|             // Now save the reminders if any.
 | ||||
|             if (options.reminders) { | ||||
|             if (options.reminders?.length) { | ||||
|                 await CoreUtils.ignoreErrors( | ||||
|                     Promise.all(options.reminders.map((reminder) => this.addEventReminder(event, reminder.time, siteId))), | ||||
|                 ); | ||||
| @ -1718,7 +1719,7 @@ export class AddonCalendarProvider { | ||||
|             const event = await this.submitEventOnline(eventId, formData, siteId); | ||||
| 
 | ||||
|             // Now save the reminders if any.
 | ||||
|             if (options.reminders) { | ||||
|             if (options.reminders?.length) { | ||||
|                 await CoreUtils.ignoreErrors( | ||||
|                     Promise.all(options.reminders.map((reminder) => this.addEventReminder(event, reminder.time, siteId))), | ||||
|                 ); | ||||
|  | ||||
| @ -22,7 +22,7 @@ import { AddonCalendar, AddonCalendarEventType, AddonCalendarProvider } from '.. | ||||
|  * Database variables for AddonCalendarProvider service. | ||||
|  */ | ||||
| export const EVENTS_TABLE = 'addon_calendar_events_3'; | ||||
| export const REMINDERS_TABLE = 'addon_calendar_reminders'; | ||||
| export const REMINDERS_TABLE = 'addon_calendar_reminders_2'; | ||||
| export const CALENDAR_SITE_SCHEMA: CoreSiteSchema = { | ||||
|     name: 'AddonCalendarProvider', | ||||
|     version: 4, | ||||
| @ -195,6 +195,10 @@ export const CALENDAR_SITE_SCHEMA: CoreSiteSchema = { | ||||
|                     name: 'time', | ||||
|                     type: 'INTEGER', | ||||
|                 }, | ||||
|                 { | ||||
|                     name: 'timecreated', | ||||
|                     type: 'INTEGER', | ||||
|                 }, | ||||
|             ], | ||||
|             uniqueKeys: [ | ||||
|                 ['eventid', 'time'], | ||||
| @ -228,7 +232,16 @@ export const CALENDAR_SITE_SCHEMA: CoreSiteSchema = { | ||||
|             } | ||||
| 
 | ||||
|             // Migrate reminders. New format @since 4.0.
 | ||||
|             const records = await db.getAllRecords<AddonCalendarReminderDBRecord>(REMINDERS_TABLE); | ||||
|             const oldTable = 'addon_calendar_reminders'; | ||||
| 
 | ||||
|             try { | ||||
|                 await db.tableExists(oldTable); | ||||
|             } catch (error) { | ||||
|                 // Old table does not exist, ignore.
 | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             const records = await db.getAllRecords<AddonCalendarReminderDBRecord>(oldTable); | ||||
|             const events: Record<number, AddonCalendarEventDBRecord> = {}; | ||||
| 
 | ||||
|             await Promise.all(records.map(async (record) => { | ||||
| @ -237,9 +250,7 @@ export const CALENDAR_SITE_SCHEMA: CoreSiteSchema = { | ||||
|                     try { | ||||
|                         events[record.eventid] = await db.getRecord(EVENTS_TABLE, { id: record.eventid }); | ||||
|                     } catch { | ||||
|                         // Event not found in local DB, shouldn't happen. Delete the reminder.
 | ||||
|                         await db.deleteRecords(REMINDERS_TABLE, { id: record.id }); | ||||
| 
 | ||||
|                         // Event not found in local DB, shouldn't happen. Ignore the reminder.
 | ||||
|                         return; | ||||
|                     } | ||||
|                 } | ||||
| @ -248,9 +259,7 @@ export const CALENDAR_SITE_SCHEMA: CoreSiteSchema = { | ||||
|                     // Default reminder. Use null now.
 | ||||
|                     record.time = null; | ||||
|                 } else if (record.time > events[record.eventid].timestart) { | ||||
|                     // Reminder is after the event, delete it.
 | ||||
|                     await db.deleteRecords(REMINDERS_TABLE, { id: record.id }); | ||||
| 
 | ||||
|                     // Reminder is after the event, ignore it.
 | ||||
|                     return; | ||||
|                 } else { | ||||
|                     // Remove seconds from the old reminder, it could include seconds by mistake.
 | ||||
| @ -259,6 +268,12 @@ export const CALENDAR_SITE_SCHEMA: CoreSiteSchema = { | ||||
| 
 | ||||
|                 return db.insertRecord(REMINDERS_TABLE, record); | ||||
|             })); | ||||
| 
 | ||||
|             try { | ||||
|                 await db.dropTable(oldTable); | ||||
|             } catch (error) { | ||||
|                 // Error deleting old table, ignore.
 | ||||
|             } | ||||
|         } | ||||
|     }, | ||||
| }; | ||||
| @ -308,4 +323,5 @@ export type AddonCalendarReminderDBRecord = { | ||||
|     id: number; | ||||
|     eventid: number; | ||||
|     time: number | null; // Number of seconds before the event, null for default time.
 | ||||
|     timecreated?: number | null; | ||||
| }; | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user