MOBILE-3909 calendar: Change reminders to time before
parent
4fa1d72a2b
commit
47c913f434
|
@ -140,6 +140,7 @@
|
|||
"addon.calendar.sunday": "calendar",
|
||||
"addon.calendar.thu": "calendar",
|
||||
"addon.calendar.thursday": "calendar",
|
||||
"addon.calendar.timebefore": "local_moodlemobileapp",
|
||||
"addon.calendar.today": "calendar",
|
||||
"addon.calendar.tomorrow": "calendar",
|
||||
"addon.calendar.tue": "calendar",
|
||||
|
@ -153,6 +154,7 @@
|
|||
"addon.calendar.typeopen": "calendar",
|
||||
"addon.calendar.typesite": "calendar",
|
||||
"addon.calendar.typeuser": "calendar",
|
||||
"addon.calendar.units": "qtype_numerical",
|
||||
"addon.calendar.upcomingevents": "calendar",
|
||||
"addon.calendar.userevents": "calendar",
|
||||
"addon.calendar.wed": "calendar",
|
||||
|
@ -1562,6 +1564,7 @@
|
|||
"core.courses.therearecourses": "moodle",
|
||||
"core.courses.totalcoursesearchresults": "local_moodlemobileapp",
|
||||
"core.currentdevice": "local_moodlemobileapp",
|
||||
"core.custom": "form",
|
||||
"core.datastoredoffline": "local_moodlemobileapp",
|
||||
"core.date": "moodle",
|
||||
"core.day": "moodle",
|
||||
|
@ -1943,6 +1946,8 @@
|
|||
"core.maxsizeandattachments": "moodle",
|
||||
"core.min": "moodle",
|
||||
"core.mins": "moodle",
|
||||
"core.minute": "moodle",
|
||||
"core.minutes": "moodle",
|
||||
"core.misc": "admin",
|
||||
"core.mod_assign": "assign/pluginname",
|
||||
"core.mod_assignment": "assignment/pluginname",
|
||||
|
@ -2283,6 +2288,8 @@
|
|||
"core.viewprofile": "moodle",
|
||||
"core.warningofflinedatadeleted": "local_moodlemobileapp",
|
||||
"core.warnopeninbrowser": "local_moodlemobileapp",
|
||||
"core.week": "moodle",
|
||||
"core.weeks": "moodle",
|
||||
"core.whatisyourage": "moodle",
|
||||
"core.wheredoyoulive": "moodle",
|
||||
"core.whoissiteadmin": "local_moodlemobileapp",
|
||||
|
|
|
@ -19,12 +19,14 @@ import { CoreSharedModule } from '@/core/shared.module';
|
|||
import { AddonCalendarCalendarComponent } from './calendar/calendar';
|
||||
import { AddonCalendarUpcomingEventsComponent } from './upcoming-events/upcoming-events';
|
||||
import { AddonCalendarFilterPopoverComponent } from './filter/filter';
|
||||
import { AddonCalendarReminderTimeModalComponent } from './reminder-time-modal/reminder-time-modal';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AddonCalendarCalendarComponent,
|
||||
AddonCalendarUpcomingEventsComponent,
|
||||
AddonCalendarFilterPopoverComponent,
|
||||
AddonCalendarReminderTimeModalComponent,
|
||||
],
|
||||
imports: [
|
||||
CoreSharedModule,
|
||||
|
@ -35,6 +37,7 @@ import { AddonCalendarFilterPopoverComponent } from './filter/filter';
|
|||
AddonCalendarCalendarComponent,
|
||||
AddonCalendarUpcomingEventsComponent,
|
||||
AddonCalendarFilterPopoverComponent,
|
||||
AddonCalendarReminderTimeModalComponent,
|
||||
],
|
||||
})
|
||||
export class AddonCalendarComponentsModule {}
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<h2>{{ 'addon.calendar.reminders' | translate }}</h2>
|
||||
<ion-buttons slot="end">
|
||||
<ion-button fill="clear" (click)="closeModal()" [attr.aria-label]="'core.close' | translate">
|
||||
<ion-icon slot="icon-only" name="fas-times" aria-hidden="true"></ion-icon>
|
||||
</ion-button>
|
||||
</ion-buttons>
|
||||
</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>
|
||||
|
||||
<!-- Custom value. -->
|
||||
<ion-item lines="none" 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>
|
||||
|
||||
<!-- 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-content>
|
|
@ -0,0 +1,156 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { AddonCalendar, AddonCalendarReminderUnits, AddonCalendarValueAndUnit } from '@addons/calendar/services/calendar';
|
||||
import { Component, Input, OnInit } from '@angular/core';
|
||||
import { CoreDomUtils } from '@services/utils/dom';
|
||||
import { ModalController } from '@singletons';
|
||||
|
||||
/**
|
||||
* Modal to choose a reminder time.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'addon-calendar-new-reminder-modal',
|
||||
templateUrl: 'reminder-time-modal.html',
|
||||
})
|
||||
export class AddonCalendarReminderTimeModalComponent implements OnInit {
|
||||
|
||||
@Input() initialValue?: AddonCalendarValueAndUnit;
|
||||
@Input() allowDisable?: boolean;
|
||||
|
||||
radioValue = '5m';
|
||||
customValue = '10';
|
||||
customUnits = AddonCalendarReminderUnits.MINUTE;
|
||||
|
||||
presetOptions = [
|
||||
{
|
||||
radioValue: '5m',
|
||||
value: 5,
|
||||
unit: AddonCalendarReminderUnits.MINUTE,
|
||||
label: '',
|
||||
},
|
||||
{
|
||||
radioValue: '10m',
|
||||
value: 10,
|
||||
unit: AddonCalendarReminderUnits.MINUTE,
|
||||
label: '',
|
||||
},
|
||||
{
|
||||
radioValue: '30m',
|
||||
value: 30,
|
||||
unit: AddonCalendarReminderUnits.MINUTE,
|
||||
label: '',
|
||||
},
|
||||
{
|
||||
radioValue: '1h',
|
||||
value: 1,
|
||||
unit: AddonCalendarReminderUnits.HOUR,
|
||||
label: '',
|
||||
},
|
||||
{
|
||||
radioValue: '12h',
|
||||
value: 12,
|
||||
unit: AddonCalendarReminderUnits.HOUR,
|
||||
label: '',
|
||||
},
|
||||
{
|
||||
radioValue: '1d',
|
||||
value: 1,
|
||||
unit: AddonCalendarReminderUnits.DAY,
|
||||
label: '',
|
||||
},
|
||||
];
|
||||
|
||||
customUnitsOptions = [
|
||||
{
|
||||
value: AddonCalendarReminderUnits.MINUTE,
|
||||
label: 'core.minutes',
|
||||
},
|
||||
{
|
||||
value: AddonCalendarReminderUnits.HOUR,
|
||||
label: 'core.hours',
|
||||
},
|
||||
{
|
||||
value: AddonCalendarReminderUnits.DAY,
|
||||
label: 'core.days',
|
||||
},
|
||||
{
|
||||
value: AddonCalendarReminderUnits.WEEK,
|
||||
label: 'core.weeks',
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
async ngOnInit(): Promise<void> {
|
||||
this.presetOptions.forEach((option) => {
|
||||
option.label = AddonCalendar.getUnitValueLabel(option.value, option.unit);
|
||||
});
|
||||
|
||||
if (!this.initialValue) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.initialValue.value === 0) {
|
||||
this.radioValue = 'disabled';
|
||||
} else {
|
||||
// Search if it's one of the preset options.
|
||||
const option = this.presetOptions.find(option =>
|
||||
option.value === this.initialValue?.value && option.unit === this.initialValue.unit);
|
||||
|
||||
if (option) {
|
||||
this.radioValue = option.radioValue;
|
||||
} else {
|
||||
// It's a custom value.
|
||||
this.radioValue = 'custom';
|
||||
this.customValue = String(this.initialValue.value);
|
||||
this.customUnits = this.initialValue.unit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the modal.
|
||||
*/
|
||||
closeModal(): void {
|
||||
ModalController.dismiss();
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the reminder.
|
||||
*/
|
||||
saveReminder(): void {
|
||||
if (this.radioValue === 'disabled') {
|
||||
ModalController.dismiss(0);
|
||||
} else if (this.radioValue === 'custom') {
|
||||
const value = parseInt(this.customValue, 10);
|
||||
if (!value) {
|
||||
CoreDomUtils.showErrorModal('core.errorinvalidform', true);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
ModalController.dismiss(Math.abs(value) * this.customUnits);
|
||||
} else {
|
||||
const option = this.presetOptions.find(option => option.radioValue === this.radioValue);
|
||||
if (!option) {
|
||||
return;
|
||||
}
|
||||
|
||||
ModalController.dismiss(option.unit * option.value);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -41,6 +41,7 @@
|
|||
"noevents": "There are no events",
|
||||
"nopermissiontoupdatecalendar": "Sorry, but you do not have permission to update the calendar event.",
|
||||
"reminders": "Reminders",
|
||||
"units": "Units",
|
||||
"repeatedevents": "Repeated events",
|
||||
"repeateditall": "Also apply changes to the other {{$a}} events in this repeat series",
|
||||
"repeateditthis": "Apply changes to this event only",
|
||||
|
@ -54,6 +55,7 @@
|
|||
"sunday": "Sunday",
|
||||
"thu": "Thu",
|
||||
"thursday": "Thursday",
|
||||
"timebefore": "{{value}} {{units}} before",
|
||||
"today": "Today",
|
||||
"tomorrow": "Tomorrow",
|
||||
"tue": "Tue",
|
||||
|
@ -73,4 +75,4 @@
|
|||
"wednesday": "Wednesday",
|
||||
"when": "When",
|
||||
"yesterday": "Yesterday"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -123,34 +123,26 @@
|
|||
</ion-label>
|
||||
</ion-item>
|
||||
<ng-container *ngFor="let reminder of reminders">
|
||||
<ion-item *ngIf="reminder.time > 0 || defaultTime > 0" class="ion-text-wrap"
|
||||
[class.item-dimmed]="(reminder.time == -1 ? (event.timestart - defaultTime) : reminder.time) <= currentTime!">
|
||||
<ion-item *ngIf="reminder.timestamp > 0" class="ion-text-wrap"
|
||||
[class.item-dimmed]="reminder.timestamp <= currentTime">
|
||||
<ion-label>
|
||||
<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>
|
||||
<p>{{ reminder.label }}</p>
|
||||
</ion-label>
|
||||
<ion-button fill="clear" (click)="cancelNotification(reminder.id, $event)"
|
||||
[attr.aria-label]="'core.delete' | translate" slot="end"
|
||||
*ngIf="(reminder.time == -1 ? (event.timestart - defaultTime) : reminder.time) > currentTime!">
|
||||
[attr.aria-label]="'core.delete' | translate" slot="end" *ngIf="reminder.timestamp > currentTime">
|
||||
<ion-icon name="fas-trash" color="danger" slot="icon-only" aria-hidden="true"></ion-icon>
|
||||
</ion-button>
|
||||
</ion-item>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="event.timestart + event.timeduration > currentTime!">
|
||||
<ng-container *ngIf="event.timestart > currentTime">
|
||||
<ion-item>
|
||||
<ion-label>
|
||||
<ion-button expand="block" color="primary" (click)="notificationPicker.open()">
|
||||
<ion-button expand="block" color="primary" (click)="addReminder()">
|
||||
{{ 'addon.calendar.setnewreminder' | translate }}
|
||||
</ion-button>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
<ion-datetime #notificationPicker hidden [(ngModel)]="notificationTimeText"
|
||||
[displayFormat]="notificationFormat" [min]="notificationMin" [max]="notificationMax"
|
||||
[doneText]="'core.add' | translate" (ionChange)="addNotificationTime()" [monthNames]="monthNames">
|
||||
</ion-datetime>
|
||||
</ng-container>
|
||||
</ion-card>
|
||||
</core-loading>
|
||||
|
|
|
@ -20,7 +20,7 @@ import {
|
|||
AddonCalendarEventToDisplay,
|
||||
AddonCalendarProvider,
|
||||
} from '../../services/calendar';
|
||||
import { AddonCalendarHelper } from '../../services/calendar-helper';
|
||||
import { AddonCalendarEventReminder, AddonCalendarHelper } from '../../services/calendar-helper';
|
||||
import { AddonCalendarOffline } from '../../services/calendar-offline';
|
||||
import { AddonCalendarSync, AddonCalendarSyncEvents, AddonCalendarSyncProvider } from '../../services/calendar-sync';
|
||||
import { CoreApp } from '@services/app';
|
||||
|
@ -36,10 +36,9 @@ import { Network, NgZone, Translate } from '@singletons';
|
|||
import { Subscription } from 'rxjs';
|
||||
import { CoreNavigator } from '@services/navigator';
|
||||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { AddonCalendarReminderDBRecord } from '../../services/database/calendar';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { CoreConstants } from '@/core/constants';
|
||||
import { CoreLang } from '@services/lang';
|
||||
import { AddonCalendarReminderTimeModalComponent } from '@addons/calendar/components/reminder-time-modal/reminder-time-modal';
|
||||
|
||||
/**
|
||||
* Page that displays a single calendar event.
|
||||
|
@ -57,13 +56,11 @@ export class AddonCalendarEventPage implements OnInit, OnDestroy {
|
|||
protected syncObserver: CoreEventObserver;
|
||||
protected manualSyncObserver: CoreEventObserver;
|
||||
protected onlineObserver: Subscription;
|
||||
protected defaultTimeChangedObserver: CoreEventObserver;
|
||||
protected currentSiteId: string;
|
||||
protected updateCurrentTime?: number;
|
||||
|
||||
eventLoaded = false;
|
||||
notificationFormat?: string;
|
||||
notificationMin?: string;
|
||||
notificationMax?: string;
|
||||
notificationTimeText?: string;
|
||||
event?: AddonCalendarEventToDisplay;
|
||||
courseId?: number;
|
||||
courseName = '';
|
||||
|
@ -72,19 +69,16 @@ export class AddonCalendarEventPage implements OnInit, OnDestroy {
|
|||
notificationsEnabled = false;
|
||||
moduleUrl = '';
|
||||
categoryPath = '';
|
||||
currentTime?: number;
|
||||
defaultTime = 0;
|
||||
reminders: AddonCalendarReminderDBRecord[] = [];
|
||||
currentTime = -1;
|
||||
reminders: AddonCalendarEventReminder[] = [];
|
||||
canEdit = false;
|
||||
hasOffline = false;
|
||||
isOnline = false;
|
||||
syncIcon = CoreConstants.ICON_LOADING; // Sync icon.
|
||||
monthNames?: string[];
|
||||
|
||||
constructor(
|
||||
protected route: ActivatedRoute,
|
||||
) {
|
||||
|
||||
this.notificationsEnabled = CoreLocalNotifications.isAvailable();
|
||||
this.siteHomeId = CoreSites.getCurrentSiteHomeId();
|
||||
this.currentSiteId = CoreSites.getCurrentSiteId();
|
||||
|
@ -121,21 +115,35 @@ export class AddonCalendarEventPage implements OnInit, OnDestroy {
|
|||
this.isOnline = CoreApp.isOnline();
|
||||
});
|
||||
});
|
||||
|
||||
// Reload reminders if default notification time changes.
|
||||
this.defaultTimeChangedObserver = CoreEvents.on(AddonCalendarProvider.DEFAULT_NOTIFICATION_TIME_CHANGED, () => {
|
||||
this.loadReminders();
|
||||
|
||||
if (this.event) {
|
||||
AddonCalendar.scheduleEventsNotifications([this.event]);
|
||||
}
|
||||
}, this.currentSiteId);
|
||||
|
||||
// Set and update current time. Use a 5 seconds error margin.
|
||||
this.currentTime = CoreTimeUtils.timestamp();
|
||||
this.updateCurrentTime = window.setInterval(() => {
|
||||
this.currentTime = CoreTimeUtils.timestamp();
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
protected async initReminders(): Promise<void> {
|
||||
if (this.notificationsEnabled) {
|
||||
this.monthNames = CoreLang.getMonthNames();
|
||||
|
||||
this.reminders = await AddonCalendar.getEventReminders(this.eventId);
|
||||
this.defaultTime = await AddonCalendar.getDefaultNotificationTime() * 60;
|
||||
|
||||
// Calculate format to use.
|
||||
this.notificationFormat =
|
||||
CoreTimeUtils.fixFormatForDatetime(CoreTimeUtils.convertPHPToMoment(
|
||||
Translate.instant('core.strftimedatetime'),
|
||||
));
|
||||
/**
|
||||
* Load reminders.
|
||||
*
|
||||
* @return Promise resolved when done.
|
||||
*/
|
||||
protected async loadReminders(): Promise<void> {
|
||||
if (!this.notificationsEnabled || !this.event) {
|
||||
return;
|
||||
}
|
||||
|
||||
const reminders = await AddonCalendar.getEventReminders(this.eventId, this.currentSiteId);
|
||||
this.reminders = await AddonCalendarHelper.formatReminders(reminders, this.event.timestart, this.currentSiteId);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -155,7 +163,6 @@ export class AddonCalendarEventPage implements OnInit, OnDestroy {
|
|||
this.syncIcon = CoreConstants.ICON_LOADING;
|
||||
|
||||
this.fetchEvent();
|
||||
this.initReminders();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -209,6 +216,10 @@ export class AddonCalendarEventPage implements OnInit, OnDestroy {
|
|||
const event = await AddonCalendar.getEventById(this.eventId);
|
||||
this.event = await AddonCalendarHelper.formatEventData(event);
|
||||
|
||||
// Load reminders, and re-schedule them if needed (maybe the event time has changed).
|
||||
this.loadReminders();
|
||||
AddonCalendar.scheduleEventsNotifications([this.event]);
|
||||
|
||||
try {
|
||||
const offlineEvent = AddonCalendarHelper.formatOfflineEventData(
|
||||
await AddonCalendarOffline.getEvent(this.eventId),
|
||||
|
@ -223,29 +234,21 @@ export class AddonCalendarEventPage implements OnInit, OnDestroy {
|
|||
this.hasOffline = false;
|
||||
}
|
||||
|
||||
this.currentTime = CoreTimeUtils.timestamp();
|
||||
this.notificationMin = CoreTimeUtils.userDate(this.currentTime * 1000, 'YYYY-MM-DDTHH:mm', false);
|
||||
this.notificationMax = CoreTimeUtils.userDate(
|
||||
(this.event!.timestart + this.event!.timeduration) * 1000,
|
||||
'YYYY-MM-DDTHH:mm',
|
||||
false,
|
||||
);
|
||||
|
||||
// Reset some of the calculated data.
|
||||
this.categoryPath = '';
|
||||
this.courseName = '';
|
||||
this.courseUrl = '';
|
||||
this.moduleUrl = '';
|
||||
|
||||
if (this.event!.moduleIcon) {
|
||||
if (this.event.moduleIcon) {
|
||||
// It's a module event, translate the module name to the current language.
|
||||
const name = CoreCourse.translateModuleName(this.event!.modulename || '');
|
||||
const name = CoreCourse.translateModuleName(this.event.modulename || '');
|
||||
if (name.indexOf('core.mod_') === -1) {
|
||||
this.event!.modulename = name;
|
||||
this.event.modulename = name;
|
||||
}
|
||||
|
||||
// Get the module URL.
|
||||
this.moduleUrl = this.event!.url || '';
|
||||
this.moduleUrl = this.event.url || '';
|
||||
}
|
||||
|
||||
const promises: Promise<void>[] = [];
|
||||
|
@ -310,22 +313,23 @@ export class AddonCalendarEventPage implements OnInit, OnDestroy {
|
|||
/**
|
||||
* Add a reminder for this event.
|
||||
*/
|
||||
async addNotificationTime(): Promise<void> {
|
||||
if (this.notificationTimeText && this.event && this.event.id) {
|
||||
let notificationTime = CoreTimeUtils.convertToTimestamp(this.notificationTimeText);
|
||||
|
||||
const currentTime = CoreTimeUtils.timestamp();
|
||||
const 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;
|
||||
}
|
||||
|
||||
await AddonCalendar.addEventReminder(this.event, notificationTime);
|
||||
this.reminders = await AddonCalendar.getEventReminders(this.eventId);
|
||||
this.notificationTimeText = undefined;
|
||||
async addReminder(): Promise<void> {
|
||||
if (!this.event || !this.event.id) {
|
||||
return;
|
||||
}
|
||||
|
||||
const reminderTime = await CoreDomUtils.openModal<number>({
|
||||
component: AddonCalendarReminderTimeModalComponent,
|
||||
});
|
||||
|
||||
if (reminderTime === undefined) {
|
||||
// User canceled.
|
||||
return;
|
||||
}
|
||||
|
||||
await AddonCalendar.addEventReminder(this.event, reminderTime, this.currentSiteId);
|
||||
|
||||
await this.loadReminders();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -345,7 +349,7 @@ export class AddonCalendarEventPage implements OnInit, OnDestroy {
|
|||
|
||||
try {
|
||||
await AddonCalendar.deleteEventReminder(id);
|
||||
this.reminders = await AddonCalendar.getEventReminders(this.eventId);
|
||||
await this.loadReminders();
|
||||
} catch (error) {
|
||||
CoreDomUtils.showErrorModalDefault(error, 'Error deleting reminder');
|
||||
} finally {
|
||||
|
@ -549,6 +553,7 @@ export class AddonCalendarEventPage implements OnInit, OnDestroy {
|
|||
this.syncObserver?.off();
|
||||
this.manualSyncObserver?.off();
|
||||
this.onlineObserver?.unsubscribe();
|
||||
clearInterval(this.updateCurrentTime);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -8,18 +8,10 @@
|
|||
</ion-header>
|
||||
<ion-content>
|
||||
<ion-list>
|
||||
<ion-item *ngIf="defaultTime != -1">
|
||||
<ion-item *ngIf="defaultTimeLabel">
|
||||
<ion-label>{{ 'addon.calendar.defaultnotificationtime' | translate }}</ion-label>
|
||||
<ion-select [(ngModel)]="defaultTime" (ionChange)="updateDefaultTime(defaultTime)" interface="action-sheet"
|
||||
[interfaceOptions]="{header: 'addon.calendar.defaultnotificationtime' | translate}">
|
||||
<ion-select-option [value]="0">{{ 'core.settings.disabled' | translate }}</ion-select-option>
|
||||
<ion-select-option [value]="10">{{ 600 | coreDuration }}</ion-select-option>
|
||||
<ion-select-option [value]="30">{{ 1800 | coreDuration }}</ion-select-option>
|
||||
<ion-select-option [value]="60">{{ 3600 | coreDuration }}</ion-select-option>
|
||||
<ion-select-option [value]="120">{{ 7200 | coreDuration }}</ion-select-option>
|
||||
<ion-select-option [value]="360">{{ 21600 | coreDuration }}</ion-select-option>
|
||||
<ion-select-option [value]="720">{{ 43200 | coreDuration }}</ion-select-option>
|
||||
<ion-select-option [value]="1440">{{ 86400 | coreDuration }}</ion-select-option>
|
||||
<ion-select [(ngModel)]="defaultTimeLabel" (click)="changeDefaultTime($event)">
|
||||
<ion-select-option [value]="defaultTimeLabel">{{ defaultTimeLabel }}</ion-select-option>
|
||||
</ion-select>
|
||||
</ion-item>
|
||||
</ion-list>
|
||||
|
|
|
@ -13,9 +13,16 @@
|
|||
// limitations under the License.
|
||||
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { AddonCalendar, AddonCalendarProvider } from '../../services/calendar';
|
||||
import {
|
||||
AddonCalendar,
|
||||
AddonCalendarProvider,
|
||||
AddonCalendarReminderUnits,
|
||||
AddonCalendarValueAndUnit,
|
||||
} from '../../services/calendar';
|
||||
import { CoreEvents } from '@singletons/events';
|
||||
import { CoreSites } from '@services/sites';
|
||||
import { CoreDomUtils } from '@services/utils/dom';
|
||||
import { AddonCalendarReminderTimeModalComponent } from '@addons/calendar/components/reminder-time-modal/reminder-time-modal';
|
||||
|
||||
/**
|
||||
* Page that displays the calendar settings.
|
||||
|
@ -26,13 +33,51 @@ import { CoreSites } from '@services/sites';
|
|||
})
|
||||
export class AddonCalendarSettingsPage implements OnInit {
|
||||
|
||||
defaultTime = -1;
|
||||
defaultTimeLabel = '';
|
||||
|
||||
protected defaultTime: AddonCalendarValueAndUnit = {
|
||||
value: 0,
|
||||
unit: AddonCalendarReminderUnits.MINUTE,
|
||||
};
|
||||
|
||||
/**
|
||||
* View loaded.
|
||||
*/
|
||||
async ngOnInit(): Promise<void> {
|
||||
this.defaultTime = await AddonCalendar.getDefaultNotificationTime();
|
||||
const defaultTime = await AddonCalendar.getDefaultNotificationTime();
|
||||
|
||||
this.defaultTime = AddonCalendarProvider.convertSecondsToValueAndUnit(defaultTime);
|
||||
this.defaultTimeLabel = AddonCalendar.getUnitValueLabel(this.defaultTime.value, this.defaultTime.unit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Change default time.
|
||||
*
|
||||
* @param e Event.
|
||||
* @return Promise resolved when done.
|
||||
*/
|
||||
async changeDefaultTime(e: Event): Promise<void> {
|
||||
e.stopPropagation();
|
||||
e.stopImmediatePropagation();
|
||||
e.preventDefault();
|
||||
|
||||
const reminderTime = await CoreDomUtils.openModal<number>({
|
||||
component: AddonCalendarReminderTimeModalComponent,
|
||||
componentProps: {
|
||||
initialValue: this.defaultTime,
|
||||
allowDisable: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (reminderTime === undefined) {
|
||||
// User canceled.
|
||||
return;
|
||||
}
|
||||
|
||||
this.defaultTime = AddonCalendarProvider.convertSecondsToValueAndUnit(reminderTime);
|
||||
this.defaultTimeLabel = AddonCalendar.getUnitValueLabel(this.defaultTime.value, this.defaultTime.unit);
|
||||
|
||||
this.updateDefaultTime(reminderTime);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -23,6 +23,7 @@ import {
|
|||
AddonCalendarEventType,
|
||||
AddonCalendarGetEventsEvent,
|
||||
AddonCalendarProvider,
|
||||
AddonCalendarReminderUnits,
|
||||
AddonCalendarWeek,
|
||||
AddonCalendarWeekDay,
|
||||
} from './calendar';
|
||||
|
@ -35,6 +36,7 @@ import { makeSingleton } from '@singletons';
|
|||
import { AddonCalendarSyncInvalidateEvent } from './calendar-sync';
|
||||
import { AddonCalendarOfflineEventDBRecord } from './database/calendar-offline';
|
||||
import { CoreCategoryData } from '@features/courses/services/courses';
|
||||
import { AddonCalendarReminderDBRecord } from './database/calendar';
|
||||
|
||||
/**
|
||||
* Context levels enumeration.
|
||||
|
@ -282,6 +284,55 @@ export class AddonCalendarHelperProvider {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Format reminders, adding calculated data.
|
||||
*
|
||||
* @param reminders Reminders.
|
||||
* @param timestart Event timestart.
|
||||
* @param siteId Site ID.
|
||||
* @return Formatted reminders.
|
||||
*/
|
||||
async formatReminders(
|
||||
reminders: AddonCalendarReminderDBRecord[],
|
||||
timestart: number,
|
||||
siteId?: string,
|
||||
): Promise<AddonCalendarEventReminder[]> {
|
||||
const defaultTime = await AddonCalendar.getDefaultNotificationTime(siteId);
|
||||
|
||||
const formattedReminders = <AddonCalendarEventReminder[]> reminders;
|
||||
const eventTimestart = timestart;
|
||||
let defaultTimeValue: number | undefined;
|
||||
let defaultTimeUnit: AddonCalendarReminderUnits | undefined;
|
||||
|
||||
if (defaultTime > 0) {
|
||||
const data = AddonCalendarProvider.convertSecondsToValueAndUnit(defaultTime);
|
||||
defaultTimeValue = data.value;
|
||||
defaultTimeUnit = data.unit;
|
||||
}
|
||||
|
||||
return formattedReminders.map((reminder) => {
|
||||
if (reminder.time === null) {
|
||||
// Default time. Check if default notifications are disabled.
|
||||
if (defaultTimeValue !== undefined && defaultTimeUnit) {
|
||||
reminder.value = defaultTimeValue;
|
||||
reminder.unit = defaultTimeUnit;
|
||||
reminder.timestamp = eventTimestart - reminder.value * reminder.unit;
|
||||
}
|
||||
} else {
|
||||
const data = AddonCalendarProvider.convertSecondsToValueAndUnit(reminder.time);
|
||||
reminder.value = data.value;
|
||||
reminder.unit = data.unit;
|
||||
reminder.timestamp = eventTimestart - reminder.time;
|
||||
}
|
||||
|
||||
if (reminder.value && reminder.unit) {
|
||||
reminder.label = AddonCalendar.getUnitValueLabel(reminder.value, reminder.unit, reminder.time === null);
|
||||
}
|
||||
|
||||
return reminder;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get options (name & value) for each allowed event type.
|
||||
*
|
||||
|
@ -725,3 +776,13 @@ export type AddonCalendarEventTypeOption = {
|
|||
name: string;
|
||||
value: AddonCalendarEventType;
|
||||
};
|
||||
|
||||
/**
|
||||
* Formatted event reminder.
|
||||
*/
|
||||
export type AddonCalendarEventReminder = AddonCalendarReminderDBRecord & {
|
||||
value?: number; // Amount of time.
|
||||
unit?: AddonCalendarReminderUnits; // Units.
|
||||
timestamp?: number; // Timestamp (in seconds).
|
||||
label?: string; // Label to represent the reminder.
|
||||
};
|
||||
|
|
|
@ -53,6 +53,16 @@ export enum AddonCalendarEventType {
|
|||
USER = 'user',
|
||||
}
|
||||
|
||||
/**
|
||||
* Units to set a reminder.
|
||||
*/
|
||||
export enum AddonCalendarReminderUnits {
|
||||
MINUTE = CoreConstants.SECONDS_MINUTE,
|
||||
HOUR = CoreConstants.SECONDS_HOUR,
|
||||
DAY = CoreConstants.SECONDS_DAY,
|
||||
WEEK = CoreConstants.SECONDS_WEEK,
|
||||
}
|
||||
|
||||
declare module '@singletons/events' {
|
||||
|
||||
/**
|
||||
|
@ -72,6 +82,21 @@ declare module '@singletons/events' {
|
|||
|
||||
}
|
||||
|
||||
const REMINDER_UNITS_LABELS = {
|
||||
single: {
|
||||
[AddonCalendarReminderUnits.MINUTE]: 'core.minute',
|
||||
[AddonCalendarReminderUnits.HOUR]: 'core.hour',
|
||||
[AddonCalendarReminderUnits.DAY]: 'core.day',
|
||||
[AddonCalendarReminderUnits.WEEK]: 'core.week',
|
||||
},
|
||||
multi: {
|
||||
[AddonCalendarReminderUnits.MINUTE]: 'core.minutes',
|
||||
[AddonCalendarReminderUnits.HOUR]: 'core.hours',
|
||||
[AddonCalendarReminderUnits.DAY]: 'core.days',
|
||||
[AddonCalendarReminderUnits.WEEK]: 'core.weeks',
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Service to handle calendar events.
|
||||
*/
|
||||
|
@ -82,7 +107,7 @@ export class AddonCalendarProvider {
|
|||
static readonly COMPONENT = 'AddonCalendarEvents';
|
||||
static readonly DEFAULT_NOTIFICATION_TIME_CHANGED = 'AddonCalendarDefaultNotificationTimeChangedEvent';
|
||||
static readonly DEFAULT_NOTIFICATION_TIME_SETTING = 'mmaCalendarDefaultNotifTime';
|
||||
static readonly DEFAULT_NOTIFICATION_TIME = 60;
|
||||
static readonly DEFAULT_NOTIFICATION_TIME = 3600;
|
||||
static readonly STARTING_WEEK_DAY = 'addon_calendar_starting_week_day';
|
||||
static readonly NEW_EVENT_EVENT = 'addon_calendar_new_event';
|
||||
static readonly NEW_EVENT_DISCARDED_EVENT = 'addon_calendar_new_event_discarded';
|
||||
|
@ -156,6 +181,41 @@ export class AddonCalendarProvider {
|
|||
return !!site?.isVersionGreaterEqualThan('3.7.1');
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a number of seconds, convert it to a unit&value format compatible with reminders.
|
||||
*
|
||||
* @param seconds Number of seconds.
|
||||
* @return Value and unit.
|
||||
*/
|
||||
static convertSecondsToValueAndUnit(seconds: number): AddonCalendarValueAndUnit {
|
||||
if (seconds <= 0) {
|
||||
return {
|
||||
value: 0,
|
||||
unit: AddonCalendarReminderUnits.MINUTE,
|
||||
};
|
||||
} else if (seconds % AddonCalendarReminderUnits.WEEK === 0) {
|
||||
return {
|
||||
value: seconds / AddonCalendarReminderUnits.WEEK,
|
||||
unit: AddonCalendarReminderUnits.WEEK,
|
||||
};
|
||||
} else if (seconds % AddonCalendarReminderUnits.DAY === 0) {
|
||||
return {
|
||||
value: seconds / AddonCalendarReminderUnits.DAY,
|
||||
unit: AddonCalendarReminderUnits.DAY,
|
||||
};
|
||||
} else if (seconds % AddonCalendarReminderUnits.HOUR === 0) {
|
||||
return {
|
||||
value: seconds / AddonCalendarReminderUnits.HOUR,
|
||||
unit: AddonCalendarReminderUnits.HOUR,
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
value: seconds / AddonCalendarReminderUnits.MINUTE,
|
||||
unit: AddonCalendarReminderUnits.MINUTE,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete an event.
|
||||
*
|
||||
|
@ -248,7 +308,7 @@ export class AddonCalendarProvider {
|
|||
REMINDERS_TABLE,
|
||||
{ eventid: eventId },
|
||||
).then((reminders) =>
|
||||
Promise.all(reminders.map((reminder) => this.deleteEventReminder(reminder.id!, siteId)))));
|
||||
Promise.all(reminders.map((reminder) => this.deleteEventReminder(reminder.id, siteId)))));
|
||||
|
||||
try {
|
||||
await Promise.all(promises);
|
||||
|
@ -548,7 +608,7 @@ export class AddonCalendarProvider {
|
|||
* Get the configured default notification time.
|
||||
*
|
||||
* @param siteId ID of the site. If not defined, use current site.
|
||||
* @return Promise resolved with the default time.
|
||||
* @return Promise resolved with the default time (in seconds).
|
||||
*/
|
||||
async getDefaultNotificationTime(siteId?: string): Promise<number> {
|
||||
siteId = siteId || CoreSites.getCurrentSiteId();
|
||||
|
@ -678,24 +738,27 @@ export class AddonCalendarProvider {
|
|||
/**
|
||||
* Adds an event reminder and schedule a new notification.
|
||||
*
|
||||
* @param event Event to update its notification time.
|
||||
* @param time New notification setting timestamp.
|
||||
* @param event Event to set the reminder.
|
||||
* @param time Amount of seconds of the reminder. Undefined for default reminder.
|
||||
* @param siteId ID of the site the event belongs to. If not defined, use current site.
|
||||
* @return Promise resolved when the notification is updated.
|
||||
*/
|
||||
async addEventReminder(
|
||||
event: { id: number; timestart: number; timeduration: number; name: string},
|
||||
time: number,
|
||||
time?: number | null,
|
||||
siteId?: string,
|
||||
): Promise<void> {
|
||||
const site = await CoreSites.getSite(siteId);
|
||||
const reminder: AddonCalendarReminderDBRecord = {
|
||||
const reminder: Partial<AddonCalendarReminderDBRecord> = {
|
||||
eventid: event.id,
|
||||
time: time,
|
||||
time: time ?? null,
|
||||
};
|
||||
|
||||
const reminderId = await site.getDb().insertRecord(REMINDERS_TABLE, reminder);
|
||||
|
||||
await this.scheduleEventNotification(event, reminderId, time, site.getId());
|
||||
const timestamp = time ? event.timestart - time : time;
|
||||
|
||||
await this.scheduleEventNotification(event, reminderId, timestamp, site.getId());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1022,6 +1085,35 @@ export class AddonCalendarProvider {
|
|||
(categoryId ? categoryId : '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a value and a unit, return the translated label.
|
||||
*
|
||||
* @param value Value.
|
||||
* @param unit Unit.
|
||||
* @param addDefaultLabel Whether to add the "Default" text.
|
||||
* @return Translated label.
|
||||
*/
|
||||
getUnitValueLabel(value: number, unit: AddonCalendarReminderUnits, addDefaultLabel = false): string {
|
||||
if (value === 0) {
|
||||
return Translate.instant('core.settings.disabled');
|
||||
}
|
||||
|
||||
const unitsLabel = value === 1 ?
|
||||
REMINDER_UNITS_LABELS.single[unit] :
|
||||
REMINDER_UNITS_LABELS.multi[unit];
|
||||
|
||||
const label = Translate.instant('addon.calendar.timebefore', {
|
||||
units: Translate.instant(unitsLabel),
|
||||
value: value,
|
||||
});
|
||||
|
||||
if (addDefaultLabel) {
|
||||
return Translate.instant('core.defaultvalue', { $a: label });
|
||||
}
|
||||
|
||||
return label;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get upcoming calendar events.
|
||||
*
|
||||
|
@ -1335,14 +1427,14 @@ export class AddonCalendarProvider {
|
|||
*
|
||||
* @param event Event to schedule.
|
||||
* @param reminderId The reminder ID.
|
||||
* @param time Notification setting time (in minutes). E.g. 10 means "notificate 10 minutes before start".
|
||||
* @param time Notification timestamp (in seconds). Undefined for default time.
|
||||
* @param siteId Site ID the event belongs to. If not defined, use current site.
|
||||
* @return Promise resolved when the notification is scheduled.
|
||||
*/
|
||||
protected async scheduleEventNotification(
|
||||
event: { id: number; timestart: number; name: string},
|
||||
reminderId: number,
|
||||
time: number,
|
||||
time?: number | null,
|
||||
siteId?: string,
|
||||
): Promise<void> {
|
||||
|
||||
|
@ -1357,16 +1449,16 @@ export class AddonCalendarProvider {
|
|||
return CoreLocalNotifications.cancel(reminderId, AddonCalendarProvider.COMPONENT, siteId);
|
||||
}
|
||||
|
||||
if (time == -1) {
|
||||
// If time is -1, get event default time to calculate the notification time.
|
||||
if (!time) {
|
||||
// Get event default time to calculate the notification time.
|
||||
time = await this.getDefaultNotificationTime(siteId);
|
||||
|
||||
if (time == 0) {
|
||||
if (time === 0) {
|
||||
// Default notification time is disabled, do not show.
|
||||
return CoreLocalNotifications.cancel(reminderId, AddonCalendarProvider.COMPONENT, siteId);
|
||||
}
|
||||
|
||||
time = event.timestart - (time * 60);
|
||||
time = event.timestart - time;
|
||||
}
|
||||
|
||||
time = time * 1000;
|
||||
|
@ -1417,17 +1509,18 @@ export class AddonCalendarProvider {
|
|||
siteId = siteId || CoreSites.getCurrentSiteId();
|
||||
|
||||
const promises = events.map(async (event) => {
|
||||
const timeEnd = (event.timestart + event.timeduration) * 1000;
|
||||
|
||||
if (timeEnd <= new Date().getTime()) {
|
||||
// The event has finished already, don't schedule it.
|
||||
if (event.timestart * 1000 <= Date.now()) {
|
||||
// The event has already started, don't schedule it.
|
||||
return this.deleteLocalEvent(event.id, siteId);
|
||||
}
|
||||
|
||||
const reminders = await this.getEventReminders(event.id, siteId);
|
||||
|
||||
const p2 = reminders.map((reminder: AddonCalendarReminderDBRecord) =>
|
||||
this.scheduleEventNotification(event, (reminder.id!), reminder.time, siteId));
|
||||
const p2 = reminders.map((reminder) => {
|
||||
const time = reminder.time ? event.timestart - reminder.time : reminder.time;
|
||||
|
||||
return this.scheduleEventNotification(event, reminder.id, time, siteId);
|
||||
});
|
||||
|
||||
await Promise.all(p2);
|
||||
});
|
||||
|
@ -1467,7 +1560,8 @@ export class AddonCalendarProvider {
|
|||
const reminders = await this.getEventReminders(event.id, siteId);
|
||||
|
||||
if (reminders.length == 0) {
|
||||
this.addEventReminder(event, -1, siteId);
|
||||
// No reminders, create the default one.
|
||||
this.addEventReminder(event, undefined, siteId);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1537,9 +1631,7 @@ export class AddonCalendarProvider {
|
|||
const site = await CoreSites.getSite(siteId);
|
||||
siteId = site.getId();
|
||||
|
||||
await Promise.all(events.map((event: AddonCalendarGetEventsEvent| AddonCalendarCalendarEvent) =>
|
||||
// If event does not exist on the DB, schedule the reminder.
|
||||
this.storeEventInLocalDb(event, siteId)));
|
||||
await Promise.all(events.map((event) => this.storeEventInLocalDb(event, siteId)));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2154,3 +2246,11 @@ type AddonCalendarPushNotificationData = {
|
|||
reminderId: number;
|
||||
siteId: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Value and unit for reminders.
|
||||
*/
|
||||
export type AddonCalendarValueAndUnit = {
|
||||
value: number;
|
||||
unit: AddonCalendarReminderUnits;
|
||||
};
|
||||
|
|
|
@ -14,7 +14,8 @@
|
|||
|
||||
import { SQLiteDB } from '@classes/sqlitedb';
|
||||
import { CoreSiteSchema } from '@services/sites';
|
||||
import { AddonCalendarEventType } from '../calendar';
|
||||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { AddonCalendar, AddonCalendarEventType } from '../calendar';
|
||||
|
||||
/**
|
||||
* Database variables for AddonDatabase service.
|
||||
|
@ -23,7 +24,7 @@ export const EVENTS_TABLE = 'addon_calendar_events_3';
|
|||
export const REMINDERS_TABLE = 'addon_calendar_reminders';
|
||||
export const CALENDAR_SITE_SCHEMA: CoreSiteSchema = {
|
||||
name: 'AddonCalendarProvider',
|
||||
version: 3,
|
||||
version: 4,
|
||||
canBeCleared: [EVENTS_TABLE],
|
||||
tables: [
|
||||
{
|
||||
|
@ -199,8 +200,9 @@ export const CALENDAR_SITE_SCHEMA: CoreSiteSchema = {
|
|||
],
|
||||
},
|
||||
],
|
||||
async migrate(db: SQLiteDB, oldVersion: number): Promise<void> {
|
||||
async migrate(db: SQLiteDB, oldVersion: number, siteId: string): Promise<void> {
|
||||
if (oldVersion < 3) {
|
||||
// Migrate calendar events. New format @since 3.7.
|
||||
let oldTable = 'addon_calendar_events_2';
|
||||
|
||||
try {
|
||||
|
@ -212,6 +214,46 @@ export const CALENDAR_SITE_SCHEMA: CoreSiteSchema = {
|
|||
|
||||
await db.migrateTable(oldTable, EVENTS_TABLE);
|
||||
}
|
||||
|
||||
if (oldVersion < 4) {
|
||||
// Migrate reminders. New format @since 4.0.
|
||||
const defaultTime = await CoreUtils.ignoreErrors(AddonCalendar.getDefaultNotificationTime(siteId));
|
||||
if (defaultTime) {
|
||||
// Convert from minutes to seconds.
|
||||
AddonCalendar.setDefaultNotificationTime(defaultTime * 60, siteId);
|
||||
}
|
||||
|
||||
const records = await db.getAllRecords<AddonCalendarReminderDBRecord>(REMINDERS_TABLE);
|
||||
const events: Record<number, AddonCalendarEventDBRecord> = {};
|
||||
|
||||
await Promise.all(records.map(async (record) => {
|
||||
// Get the event to compare the reminder time with the event time.
|
||||
if (!events[record.eventid]) {
|
||||
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 });
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!record.time || record.time === -1) {
|
||||
// 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 });
|
||||
|
||||
return;
|
||||
} else {
|
||||
record.time = events[record.eventid].timestart - record.time;
|
||||
}
|
||||
|
||||
return this.insertRecord(REMINDERS_TABLE, record);
|
||||
}));
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -257,7 +299,7 @@ export type AddonCalendarEventDBRecord = {
|
|||
};
|
||||
|
||||
export type AddonCalendarReminderDBRecord = {
|
||||
id?: number;
|
||||
id: number;
|
||||
eventid: number;
|
||||
time: number;
|
||||
time: number | null; // Number of seconds before the event, null for default time.
|
||||
};
|
||||
|
|
|
@ -60,6 +60,7 @@
|
|||
"coursedetails": "Course details",
|
||||
"coursenogroups": "You are not a member of any group of this course.",
|
||||
"currentdevice": "Current device",
|
||||
"custom": "Custom",
|
||||
"datastoredoffline": "Data stored in the device because it couldn't be sent. It will be sent automatically later.",
|
||||
"date": "Date",
|
||||
"day": "day",
|
||||
|
@ -157,6 +158,8 @@
|
|||
"maxsizeandattachments": "Maximum file size: {{$a.size}}, maximum number of files: {{$a.attachments}}",
|
||||
"min": "min",
|
||||
"mins": "mins",
|
||||
"minute": "minute",
|
||||
"minutes": "minutes",
|
||||
"misc": "Miscellaneous",
|
||||
"mod_assign": "Assignment",
|
||||
"mod_assignment": "Assignment 2.2 (Disabled)",
|
||||
|
@ -330,6 +333,8 @@
|
|||
"viewprofile": "View profile",
|
||||
"warningofflinedatadeleted": "Offline data from {{component}} '{{name}}' has been deleted. {{error}}",
|
||||
"warnopeninbrowser": "<p>You are about to leave the app to open the following URL in your device's browser. Do you want to continue?</p>\n<p><b>{{url}}</b></p>",
|
||||
"week": "week",
|
||||
"weeks": "weeks",
|
||||
"whatisyourage": "What is your age?",
|
||||
"wheredoyoulive": "In which country do you live?",
|
||||
"whoissiteadmin": "\"Site Administrators\" are the people who manage the Moodle at your school/university/company or learning organisation. If you don't know how to contact them, please contact your teachers/trainers.",
|
||||
|
|
Loading…
Reference in New Issue