Merge pull request #3043 from dpalou/MOBILE-3951
MOBILE-3951 calendar: Schedule notifications from servicemain
commit
af9e1ce486
|
@ -18,9 +18,9 @@ jobs:
|
||||||
node-version: '${{ steps.nvmrc.outputs.node_version }}'
|
node-version: '${{ steps.nvmrc.outputs.node_version }}'
|
||||||
- name: Additional checkouts
|
- name: Additional checkouts
|
||||||
run: |
|
run: |
|
||||||
git clone --branch master --depth 1 git://github.com/moodle/moodle $GITHUB_WORKSPACE/moodle
|
git clone --branch master --depth 1 https://github.com/moodle/moodle $GITHUB_WORKSPACE/moodle
|
||||||
git clone --branch integration --depth 1 git://github.com/moodlehq/moodle-local_moodlemobileapp $GITHUB_WORKSPACE/moodle/local/moodlemobileapp
|
git clone --branch integration --depth 1 https://github.com/moodlehq/moodle-local_moodlemobileapp $GITHUB_WORKSPACE/moodle/local/moodlemobileapp
|
||||||
git clone --branch master --depth 1 git://github.com/moodlehq/moodle-docker $GITHUB_WORKSPACE/moodle-docker
|
git clone --branch master --depth 1 https://github.com/moodlehq/moodle-docker $GITHUB_WORKSPACE/moodle-docker
|
||||||
- name: Install npm packages
|
- name: Install npm packages
|
||||||
run: npm ci
|
run: npm ci
|
||||||
- name: Generate Behat tests plugin
|
- name: Generate Behat tests plugin
|
||||||
|
|
|
@ -41,7 +41,6 @@ import { AddonCalendarFilter, AddonCalendarHelper } from '../../services/calenda
|
||||||
import { AddonCalendarOffline } from '../../services/calendar-offline';
|
import { AddonCalendarOffline } from '../../services/calendar-offline';
|
||||||
import { CoreCategoryData, CoreCourses } from '@features/courses/services/courses';
|
import { CoreCategoryData, CoreCourses } from '@features/courses/services/courses';
|
||||||
import { CoreApp } from '@services/app';
|
import { CoreApp } from '@services/app';
|
||||||
import { CoreLocalNotifications } from '@services/local-notifications';
|
|
||||||
import { CoreSwipeSlidesComponent } from '@components/swipe-slides/swipe-slides';
|
import { CoreSwipeSlidesComponent } from '@components/swipe-slides/swipe-slides';
|
||||||
import {
|
import {
|
||||||
CoreSwipeSlidesDynamicItem,
|
CoreSwipeSlidesDynamicItem,
|
||||||
|
@ -78,7 +77,6 @@ export class AddonCalendarCalendarComponent implements OnInit, DoCheck, OnDestro
|
||||||
protected differ: KeyValueDiffer<unknown, unknown>; // To detect changes in the data input.
|
protected differ: KeyValueDiffer<unknown, unknown>; // To detect changes in the data input.
|
||||||
// Observers and listeners.
|
// Observers and listeners.
|
||||||
protected undeleteEventObserver: CoreEventObserver;
|
protected undeleteEventObserver: CoreEventObserver;
|
||||||
protected obsDefaultTimeChange?: CoreEventObserver;
|
|
||||||
protected managerUnsubscribe?: () => void;
|
protected managerUnsubscribe?: () => void;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
@ -86,23 +84,6 @@ export class AddonCalendarCalendarComponent implements OnInit, DoCheck, OnDestro
|
||||||
) {
|
) {
|
||||||
this.currentSiteId = CoreSites.getCurrentSiteId();
|
this.currentSiteId = CoreSites.getCurrentSiteId();
|
||||||
|
|
||||||
if (CoreLocalNotifications.isAvailable()) {
|
|
||||||
// Re-schedule events if default time changes.
|
|
||||||
this.obsDefaultTimeChange = CoreEvents.on(AddonCalendarProvider.DEFAULT_NOTIFICATION_TIME_CHANGED, () => {
|
|
||||||
this.manager?.getSource().getItems()?.forEach((month) => {
|
|
||||||
if (!month.loaded) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
month.weeks?.forEach((week) => {
|
|
||||||
week.days.forEach((day) => {
|
|
||||||
AddonCalendar.scheduleEventsNotifications(day.eventsFormated || []);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}, this.currentSiteId);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Listen for events "undeleted" (offline).
|
// Listen for events "undeleted" (offline).
|
||||||
this.undeleteEventObserver = CoreEvents.on(
|
this.undeleteEventObserver = CoreEvents.on(
|
||||||
AddonCalendarProvider.UNDELETED_EVENT_EVENT,
|
AddonCalendarProvider.UNDELETED_EVENT_EVENT,
|
||||||
|
@ -329,7 +310,6 @@ export class AddonCalendarCalendarComponent implements OnInit, DoCheck, OnDestro
|
||||||
*/
|
*/
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
this.undeleteEventObserver?.off();
|
this.undeleteEventObserver?.off();
|
||||||
this.obsDefaultTimeChange?.off();
|
|
||||||
this.managerUnsubscribe && this.managerUnsubscribe();
|
this.managerUnsubscribe && this.managerUnsubscribe();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -577,13 +557,6 @@ class AddonCalendarMonthSlidesItemsManagerSource extends CoreSwipeSlidesDynamicI
|
||||||
|
|
||||||
weeks.forEach((week) => {
|
weeks.forEach((week) => {
|
||||||
week.days.forEach((day) => {
|
week.days.forEach((day) => {
|
||||||
|
|
||||||
// Schedule notifications for the events retrieved (only future events will be scheduled).
|
|
||||||
AddonCalendar.scheduleEventsNotifications(day.eventsFormated || []);
|
|
||||||
|
|
||||||
if (monthOfflineEvents || this.deletedEvents.length) {
|
|
||||||
// There is offline data, merge it.
|
|
||||||
|
|
||||||
if (this.deletedEvents.length) {
|
if (this.deletedEvents.length) {
|
||||||
// Mark as deleted the events that were deleted in offline.
|
// Mark as deleted the events that were deleted in offline.
|
||||||
day.eventsFormated?.forEach((event) => {
|
day.eventsFormated?.forEach((event) => {
|
||||||
|
@ -601,7 +574,6 @@ class AddonCalendarMonthSlidesItemsManagerSource extends CoreSwipeSlidesDynamicI
|
||||||
day.eventsFormated =
|
day.eventsFormated =
|
||||||
AddonCalendarHelper.sortEvents(day.eventsFormated.concat(monthOfflineEvents[day.mday]));
|
AddonCalendarHelper.sortEvents(day.eventsFormated.concat(monthOfflineEvents[day.mday]));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,6 @@ import { AddonCalendarHelper, AddonCalendarFilter } from '../../services/calenda
|
||||||
import { AddonCalendarOffline } from '../../services/calendar-offline';
|
import { AddonCalendarOffline } from '../../services/calendar-offline';
|
||||||
import { CoreCategoryData, CoreCourses } from '@features/courses/services/courses';
|
import { CoreCategoryData, CoreCourses } from '@features/courses/services/courses';
|
||||||
import { CoreConstants } from '@/core/constants';
|
import { CoreConstants } from '@/core/constants';
|
||||||
import { CoreLocalNotifications } from '@services/local-notifications';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component that displays upcoming events.
|
* Component that displays upcoming events.
|
||||||
|
@ -58,19 +57,12 @@ export class AddonCalendarUpcomingEventsComponent implements OnInit, DoCheck, On
|
||||||
|
|
||||||
// Observers.
|
// Observers.
|
||||||
protected undeleteEventObserver: CoreEventObserver;
|
protected undeleteEventObserver: CoreEventObserver;
|
||||||
protected obsDefaultTimeChange?: CoreEventObserver;
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
differs: KeyValueDiffers,
|
differs: KeyValueDiffers,
|
||||||
) {
|
) {
|
||||||
this.currentSiteId = CoreSites.getCurrentSiteId();
|
this.currentSiteId = CoreSites.getCurrentSiteId();
|
||||||
|
|
||||||
if (CoreLocalNotifications.isAvailable()) { // Re-schedule events if default time changes.
|
|
||||||
this.obsDefaultTimeChange = CoreEvents.on(AddonCalendarProvider.DEFAULT_NOTIFICATION_TIME_CHANGED, () => {
|
|
||||||
AddonCalendar.scheduleEventsNotifications(this.onlineEvents);
|
|
||||||
}, this.currentSiteId);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Listen for events "undeleted" (offline).
|
// Listen for events "undeleted" (offline).
|
||||||
this.undeleteEventObserver = CoreEvents.on(
|
this.undeleteEventObserver = CoreEvents.on(
|
||||||
AddonCalendarProvider.UNDELETED_EVENT_EVENT,
|
AddonCalendarProvider.UNDELETED_EVENT_EVENT,
|
||||||
|
@ -174,8 +166,6 @@ export class AddonCalendarUpcomingEventsComponent implements OnInit, DoCheck, On
|
||||||
// Don't pass courseId and categoryId, we'll filter them locally.
|
// Don't pass courseId and categoryId, we'll filter them locally.
|
||||||
const result = await AddonCalendar.getUpcomingEvents();
|
const result = await AddonCalendar.getUpcomingEvents();
|
||||||
this.onlineEvents = await Promise.all(result.events.map((event) => AddonCalendarHelper.formatEventData(event)));
|
this.onlineEvents = await Promise.all(result.events.map((event) => AddonCalendarHelper.formatEventData(event)));
|
||||||
// Schedule notifications for the events retrieved.
|
|
||||||
AddonCalendar.scheduleEventsNotifications(this.onlineEvents);
|
|
||||||
// Merge the online events with offline data.
|
// Merge the online events with offline data.
|
||||||
this.events = this.mergeEvents();
|
this.events = this.mergeEvents();
|
||||||
// Filter events by course.
|
// Filter events by course.
|
||||||
|
@ -313,7 +303,6 @@ export class AddonCalendarUpcomingEventsComponent implements OnInit, DoCheck, On
|
||||||
*/
|
*/
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
this.undeleteEventObserver?.off();
|
this.undeleteEventObserver?.off();
|
||||||
this.obsDefaultTimeChange?.off();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,6 @@ import { Component, OnInit, OnDestroy, ViewChild } from '@angular/core';
|
||||||
import { IonRefresher } from '@ionic/angular';
|
import { IonRefresher } from '@ionic/angular';
|
||||||
import { CoreApp } from '@services/app';
|
import { CoreApp } from '@services/app';
|
||||||
import { CoreEventObserver, CoreEvents } from '@singletons/events';
|
import { CoreEventObserver, CoreEvents } from '@singletons/events';
|
||||||
import { CoreLocalNotifications } from '@services/local-notifications';
|
|
||||||
import { CoreSites } from '@services/sites';
|
import { CoreSites } from '@services/sites';
|
||||||
import { CoreDomUtils } from '@services/utils/dom';
|
import { CoreDomUtils } from '@services/utils/dom';
|
||||||
import { CoreTimeUtils } from '@services/utils/time';
|
import { CoreTimeUtils } from '@services/utils/time';
|
||||||
|
@ -70,7 +69,6 @@ export class AddonCalendarDayPage implements OnInit, OnDestroy {
|
||||||
protected syncObserver: CoreEventObserver;
|
protected syncObserver: CoreEventObserver;
|
||||||
protected manualSyncObserver: CoreEventObserver;
|
protected manualSyncObserver: CoreEventObserver;
|
||||||
protected onlineObserver: Subscription;
|
protected onlineObserver: Subscription;
|
||||||
protected obsDefaultTimeChange?: CoreEventObserver;
|
|
||||||
protected filterChangedObserver: CoreEventObserver;
|
protected filterChangedObserver: CoreEventObserver;
|
||||||
protected managerUnsubscribe?: () => void;
|
protected managerUnsubscribe?: () => void;
|
||||||
|
|
||||||
|
@ -93,15 +91,6 @@ export class AddonCalendarDayPage implements OnInit, OnDestroy {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.currentSiteId = CoreSites.getCurrentSiteId();
|
this.currentSiteId = CoreSites.getCurrentSiteId();
|
||||||
|
|
||||||
if (CoreLocalNotifications.isAvailable()) {
|
|
||||||
// Re-schedule events if default time changes.
|
|
||||||
this.obsDefaultTimeChange = CoreEvents.on(AddonCalendarProvider.DEFAULT_NOTIFICATION_TIME_CHANGED, () => {
|
|
||||||
this.manager?.getSource().getItems()?.forEach(day => {
|
|
||||||
AddonCalendar.scheduleEventsNotifications(day.onlineEvents || []);
|
|
||||||
});
|
|
||||||
}, this.currentSiteId);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Listen for events added. When an event is added, reload the data.
|
// Listen for events added. When an event is added, reload the data.
|
||||||
this.newEventObserver = CoreEvents.on(
|
this.newEventObserver = CoreEvents.on(
|
||||||
AddonCalendarProvider.NEW_EVENT_EVENT,
|
AddonCalendarProvider.NEW_EVENT_EVENT,
|
||||||
|
@ -464,7 +453,6 @@ export class AddonCalendarDayPage implements OnInit, OnDestroy {
|
||||||
this.manualSyncObserver?.off();
|
this.manualSyncObserver?.off();
|
||||||
this.onlineObserver?.unsubscribe();
|
this.onlineObserver?.unsubscribe();
|
||||||
this.filterChangedObserver?.off();
|
this.filterChangedObserver?.off();
|
||||||
this.obsDefaultTimeChange?.off();
|
|
||||||
this.managerUnsubscribe && this.managerUnsubscribe();
|
this.managerUnsubscribe && this.managerUnsubscribe();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -684,9 +672,6 @@ class AddonCalendarDaySlidesItemsManagerSource extends CoreSwipeSlidesDynamicIte
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Schedule notifications for the events retrieved (only future events will be scheduled).
|
|
||||||
AddonCalendar.scheduleEventsNotifications(preloadedDay.onlineEvents || []);
|
|
||||||
|
|
||||||
// Merge the online events with offline data.
|
// Merge the online events with offline data.
|
||||||
preloadedDay.events = this.mergeEvents(preloadedDay);
|
preloadedDay.events = this.mergeEvents(preloadedDay);
|
||||||
|
|
||||||
|
|
|
@ -129,10 +129,6 @@ export class AddonCalendarEventPage implements OnInit, OnDestroy {
|
||||||
// Reload reminders if default notification time changes.
|
// Reload reminders if default notification time changes.
|
||||||
this.defaultTimeChangedObserver = CoreEvents.on(AddonCalendarProvider.DEFAULT_NOTIFICATION_TIME_CHANGED, () => {
|
this.defaultTimeChangedObserver = CoreEvents.on(AddonCalendarProvider.DEFAULT_NOTIFICATION_TIME_CHANGED, () => {
|
||||||
this.loadReminders();
|
this.loadReminders();
|
||||||
|
|
||||||
if (this.event) {
|
|
||||||
AddonCalendar.scheduleEventsNotifications([this.event]);
|
|
||||||
}
|
|
||||||
}, this.currentSiteId);
|
}, this.currentSiteId);
|
||||||
|
|
||||||
// Set and update current time. Use a 5 seconds error margin.
|
// Set and update current time. Use a 5 seconds error margin.
|
||||||
|
@ -225,9 +221,8 @@ export class AddonCalendarEventPage implements OnInit, OnDestroy {
|
||||||
return; // At this point we should always have the event, adding this check to avoid TS errors.
|
return; // At this point we should always have the event, adding this check to avoid TS errors.
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load reminders, and re-schedule them if needed (maybe the event time has changed).
|
// Load reminders.
|
||||||
this.loadReminders();
|
this.loadReminders();
|
||||||
AddonCalendar.scheduleEventsNotifications([this.event]);
|
|
||||||
|
|
||||||
// Reset some of the calculated data.
|
// Reset some of the calculated data.
|
||||||
this.categoryPath = '';
|
this.categoryPath = '';
|
||||||
|
|
|
@ -39,6 +39,7 @@ import { SafeUrl } from '@angular/platform-browser';
|
||||||
import { CoreNavigator } from '@services/navigator';
|
import { CoreNavigator } from '@services/navigator';
|
||||||
import { AddonCalendarFilter } from './calendar-helper';
|
import { AddonCalendarFilter } from './calendar-helper';
|
||||||
import { AddonCalendarSyncEvents, AddonCalendarSyncProvider } from './calendar-sync';
|
import { AddonCalendarSyncEvents, AddonCalendarSyncProvider } from './calendar-sync';
|
||||||
|
import { CoreEvents } from '@singletons/events';
|
||||||
|
|
||||||
const ROOT_CACHE_KEY = 'mmaCalendar:';
|
const ROOT_CACHE_KEY = 'mmaCalendar:';
|
||||||
|
|
||||||
|
@ -351,6 +352,28 @@ export class AddonCalendarProvider {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (CoreLocalNotifications.isAvailable()) {
|
||||||
|
CoreEvents.on(AddonCalendarProvider.DEFAULT_NOTIFICATION_TIME_CHANGED, async (data) => {
|
||||||
|
const site = await CoreSites.getSite(data.siteId);
|
||||||
|
|
||||||
|
// Get all the events that have a default reminder.
|
||||||
|
const query = 'SELECT events.*, reminders.id AS reminderid ' +
|
||||||
|
'FROM ' + EVENTS_TABLE + ' events ' +
|
||||||
|
'INNER JOIN ' + REMINDERS_TABLE + ' reminders ON events.id = reminders.eventid ' +
|
||||||
|
'WHERE reminders.time IS NULL';
|
||||||
|
|
||||||
|
const result = await site.getDb().execute(query);
|
||||||
|
|
||||||
|
// Reschedule all the default reminders.
|
||||||
|
for (let i = 0; i < result.rows.length; i++) {
|
||||||
|
const event = result.rows.item(i) as AddonCalendarEventDBRecord & {
|
||||||
|
reminderid: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.scheduleEventNotification(event, event.reminderid, null, site.getId());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -674,6 +697,9 @@ export class AddonCalendarProvider {
|
||||||
const response: AddonCalendarGetCalendarEventByIdWSResponse =
|
const response: AddonCalendarGetCalendarEventByIdWSResponse =
|
||||||
await site.read('core_calendar_get_calendar_event_by_id', params, preSets);
|
await site.read('core_calendar_get_calendar_event_by_id', params, preSets);
|
||||||
|
|
||||||
|
this.storeEventInLocalDb(response.event, { siteId });
|
||||||
|
this.scheduleEventsNotifications([response.event], siteId);
|
||||||
|
|
||||||
return response.event;
|
return response.event;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
try {
|
try {
|
||||||
|
@ -837,6 +863,7 @@ export class AddonCalendarProvider {
|
||||||
}
|
}
|
||||||
const response: AddonCalendarCalendarDay = await site.read('core_calendar_get_calendar_day_view', params, preSets);
|
const response: AddonCalendarCalendarDay = await site.read('core_calendar_get_calendar_day_view', params, preSets);
|
||||||
this.storeEventsInLocalDB(response.events, { siteId });
|
this.storeEventsInLocalDB(response.events, { siteId });
|
||||||
|
this.scheduleEventsNotifications(response.events, siteId);
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
@ -1040,7 +1067,8 @@ export class AddonCalendarProvider {
|
||||||
const response = await site.read<AddonCalendarMonth>('core_calendar_get_calendar_monthly_view', params, preSets);
|
const response = await site.read<AddonCalendarMonth>('core_calendar_get_calendar_monthly_view', params, preSets);
|
||||||
response.weeks.forEach((week) => {
|
response.weeks.forEach((week) => {
|
||||||
week.days.forEach((day) => {
|
week.days.forEach((day) => {
|
||||||
this.storeEventsInLocalDB(day.events as AddonCalendarCalendarEvent[], { siteId });
|
this.storeEventsInLocalDB(day.events, { siteId });
|
||||||
|
this.scheduleEventsNotifications(day.events, siteId);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1154,6 +1182,7 @@ export class AddonCalendarProvider {
|
||||||
|
|
||||||
const response = await site.read<AddonCalendarUpcoming>('core_calendar_get_calendar_upcoming_view', params, preSets);
|
const response = await site.read<AddonCalendarUpcoming>('core_calendar_get_calendar_upcoming_view', params, preSets);
|
||||||
this.storeEventsInLocalDB(response.events, { siteId });
|
this.storeEventsInLocalDB(response.events, { siteId });
|
||||||
|
this.scheduleEventsNotifications(response.events, siteId);
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
@ -1512,7 +1541,7 @@ export class AddonCalendarProvider {
|
||||||
const promises = events.map(async (event) => {
|
const promises = events.map(async (event) => {
|
||||||
if (event.timestart * 1000 <= Date.now()) {
|
if (event.timestart * 1000 <= Date.now()) {
|
||||||
// The event has already started, don't schedule it.
|
// The event has already started, don't schedule it.
|
||||||
return this.deleteLocalEvent(event.id, siteId);
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const reminders = await this.getEventReminders(event.id, siteId);
|
const reminders = await this.getEventReminders(event.id, siteId);
|
||||||
|
|
Loading…
Reference in New Issue