MOBILE-3136 calendar: Add filter events by type

main
Pau Ferrer Ocaña 2019-09-04 13:33:08 +02:00
parent af25b287d4
commit 343743ab09
19 changed files with 356 additions and 154 deletions

View File

@ -89,8 +89,10 @@
"addon.calendar.calendarevent": "local_moodlemobileapp", "addon.calendar.calendarevent": "local_moodlemobileapp",
"addon.calendar.calendarevents": "local_moodlemobileapp", "addon.calendar.calendarevents": "local_moodlemobileapp",
"addon.calendar.calendarreminders": "local_moodlemobileapp", "addon.calendar.calendarreminders": "local_moodlemobileapp",
"addon.calendar.categoryevents": "calendar",
"addon.calendar.confirmeventdelete": "calendar", "addon.calendar.confirmeventdelete": "calendar",
"addon.calendar.confirmeventseriesdelete": "calendar", "addon.calendar.confirmeventseriesdelete": "calendar",
"addon.calendar.courseevents": "calendar",
"addon.calendar.currentmonth": "local_moodlemobileapp", "addon.calendar.currentmonth": "local_moodlemobileapp",
"addon.calendar.daynext": "calendar", "addon.calendar.daynext": "calendar",
"addon.calendar.dayprev": "calendar", "addon.calendar.dayprev": "calendar",
@ -114,6 +116,7 @@
"addon.calendar.fri": "calendar", "addon.calendar.fri": "calendar",
"addon.calendar.friday": "calendar", "addon.calendar.friday": "calendar",
"addon.calendar.gotoactivity": "calendar", "addon.calendar.gotoactivity": "calendar",
"addon.calendar.groupevents": "calendar",
"addon.calendar.invalidtimedurationminutes": "calendar", "addon.calendar.invalidtimedurationminutes": "calendar",
"addon.calendar.invalidtimedurationuntil": "calendar", "addon.calendar.invalidtimedurationuntil": "calendar",
"addon.calendar.mon": "calendar", "addon.calendar.mon": "calendar",
@ -131,6 +134,7 @@
"addon.calendar.sat": "calendar", "addon.calendar.sat": "calendar",
"addon.calendar.saturday": "calendar", "addon.calendar.saturday": "calendar",
"addon.calendar.setnewreminder": "local_moodlemobileapp", "addon.calendar.setnewreminder": "local_moodlemobileapp",
"addon.calendar.siteevents": "calendar",
"addon.calendar.sun": "calendar", "addon.calendar.sun": "calendar",
"addon.calendar.sunday": "calendar", "addon.calendar.sunday": "calendar",
"addon.calendar.thu": "calendar", "addon.calendar.thu": "calendar",
@ -149,6 +153,7 @@
"addon.calendar.typesite": "calendar", "addon.calendar.typesite": "calendar",
"addon.calendar.typeuser": "calendar", "addon.calendar.typeuser": "calendar",
"addon.calendar.upcomingevents": "calendar", "addon.calendar.upcomingevents": "calendar",
"addon.calendar.userevents": "calendar",
"addon.calendar.wed": "calendar", "addon.calendar.wed": "calendar",
"addon.calendar.wednesday": "calendar", "addon.calendar.wednesday": "calendar",
"addon.calendar.when": "calendar", "addon.calendar.when": "calendar",
@ -1519,6 +1524,7 @@
"core.fileuploader.uploading": "local_moodlemobileapp", "core.fileuploader.uploading": "local_moodlemobileapp",
"core.fileuploader.uploadingperc": "local_moodlemobileapp", "core.fileuploader.uploadingperc": "local_moodlemobileapp",
"core.fileuploader.video": "local_moodlemobileapp", "core.fileuploader.video": "local_moodlemobileapp",
"core.filter": "moodle",
"core.folder": "moodle", "core.folder": "moodle",
"core.forcepasswordchangenotice": "moodle", "core.forcepasswordchangenotice": "moodle",
"core.fulllistofcourses": "moodle", "core.fulllistofcourses": "moodle",

View File

@ -27,6 +27,7 @@ import { CoreLocalNotificationsProvider } from '@providers/local-notifications';
import { CoreLoginHelperProvider } from '@core/login/providers/helper'; import { CoreLoginHelperProvider } from '@core/login/providers/helper';
import { CoreUpdateManagerProvider } from '@providers/update-manager'; import { CoreUpdateManagerProvider } from '@providers/update-manager';
import { CoreContentLinksDelegate } from '@core/contentlinks/providers/delegate'; import { CoreContentLinksDelegate } from '@core/contentlinks/providers/delegate';
import { AddonCalendarComponentsModule } from './components/components.module';
// List of providers (without handlers). // List of providers (without handlers).
export const ADDON_CALENDAR_PROVIDERS: any[] = [ export const ADDON_CALENDAR_PROVIDERS: any[] = [
@ -40,6 +41,7 @@ export const ADDON_CALENDAR_PROVIDERS: any[] = [
declarations: [ declarations: [
], ],
imports: [ imports: [
AddonCalendarComponentsModule,
], ],
providers: [ providers: [
AddonCalendarProvider, AddonCalendarProvider,

View File

@ -10,7 +10,8 @@ $calendar-border-color: $gray !default;
ion-app.app-root page-addon-calendar-list, ion-app.app-root page-addon-calendar-list,
ion-app.app-root page-addon-calendar-day, ion-app.app-root page-addon-calendar-day,
ion-app.app-root addon-calendar-upcoming-events { ion-app.app-root addon-calendar-upcoming-events,
ion-app.app-root addon-calendar-filter-popover {
.item.addon-calendar-event { .item.addon-calendar-event {
> .icon { > .icon {
@ -49,6 +50,26 @@ ion-app.app-root addon-calendar-upcoming-events {
} }
} }
ion-app.app-root addon-calendar-filter-popover .item.addon-calendar-event {
ion-icon[item-start] + .item-inner {
@include margin-horizontal(8px, 0);
}
> .icon {
width: 28px;
height: 28px;
line-height: 28px;
font-size: 20px;
&.fa {
font-size: 16px;
&::before {
width: 1.8em;
}
}
}
}
ion-app.app-root addon-calendar-calendar { ion-app.app-root addon-calendar-calendar {
.addon-calendar-navigation { .addon-calendar-navigation {

View File

@ -12,7 +12,8 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
import { Component, OnDestroy, OnInit, Input, OnChanges, SimpleChange, Output, EventEmitter } from '@angular/core'; import { Component, OnDestroy, OnInit, Input, OnChanges, DoCheck, SimpleChange, Output, EventEmitter,
KeyValueDiffers } from '@angular/core';
import { CoreEventsProvider } from '@providers/events'; import { CoreEventsProvider } from '@providers/events';
import { CoreLocalNotificationsProvider } from '@providers/local-notifications'; import { CoreLocalNotificationsProvider } from '@providers/local-notifications';
import { CoreSitesProvider } from '@providers/sites'; import { CoreSitesProvider } from '@providers/sites';
@ -32,11 +33,10 @@ import { CoreAppProvider } from '@providers/app';
selector: 'addon-calendar-calendar', selector: 'addon-calendar-calendar',
templateUrl: 'addon-calendar-calendar.html', templateUrl: 'addon-calendar-calendar.html',
}) })
export class AddonCalendarCalendarComponent implements OnInit, OnChanges, OnDestroy { export class AddonCalendarCalendarComponent implements OnInit, OnChanges, DoCheck, OnDestroy {
@Input() initialYear: number | string; // Initial year to load. @Input() initialYear: number | string; // Initial year to load.
@Input() initialMonth: number | string; // Initial month to load. @Input() initialMonth: number | string; // Initial month to load.
@Input() courseId: number | string; @Input() filter: any; // Filter to apply.
@Input() categoryId: number | string; // Category ID the course belongs to.
@Input() canNavigate?: string | boolean; // Whether to include arrows to change the month. Defaults to true. @Input() canNavigate?: string | boolean; // Whether to include arrows to change the month. Defaults to true.
@Input() displayNavButtons?: string | boolean; // Whether to display nav buttons created by this component. Defaults to true. @Input() displayNavButtons?: string | boolean; // Whether to display nav buttons created by this component. Defaults to true.
@Output() onEventClicked = new EventEmitter<number>(); @Output() onEventClicked = new EventEmitter<number>();
@ -59,6 +59,7 @@ export class AddonCalendarCalendarComponent implements OnInit, OnChanges, OnDest
protected offlineEditedEventsIds = []; // IDs of events edited in offline. protected offlineEditedEventsIds = []; // IDs of events edited in offline.
protected deletedEvents = []; // Events deleted in offline. protected deletedEvents = []; // Events deleted in offline.
protected currentTime: number; protected currentTime: number;
protected differ: any; // To detect changes in the data input.
// Observers. // Observers.
protected undeleteEventObserver: any; protected undeleteEventObserver: any;
@ -67,6 +68,7 @@ export class AddonCalendarCalendarComponent implements OnInit, OnChanges, OnDest
constructor(eventsProvider: CoreEventsProvider, constructor(eventsProvider: CoreEventsProvider,
sitesProvider: CoreSitesProvider, sitesProvider: CoreSitesProvider,
localNotificationsProvider: CoreLocalNotificationsProvider, localNotificationsProvider: CoreLocalNotificationsProvider,
differs: KeyValueDiffers,
private calendarProvider: AddonCalendarProvider, private calendarProvider: AddonCalendarProvider,
private calendarHelper: AddonCalendarHelperProvider, private calendarHelper: AddonCalendarHelperProvider,
private calendarOffline: AddonCalendarOfflineProvider, private calendarOffline: AddonCalendarOfflineProvider,
@ -102,6 +104,8 @@ export class AddonCalendarCalendarComponent implements OnInit, OnChanges, OnDest
} }
} }
}, this.currentSiteId); }, this.currentSiteId);
this.differ = differs.find([]).create();
} }
/** /**
@ -125,9 +129,18 @@ export class AddonCalendarCalendarComponent implements OnInit, OnChanges, OnDest
this.canNavigate = typeof this.canNavigate == 'undefined' ? true : this.utils.isTrueOrOne(this.canNavigate); this.canNavigate = typeof this.canNavigate == 'undefined' ? true : this.utils.isTrueOrOne(this.canNavigate);
this.displayNavButtons = typeof this.displayNavButtons == 'undefined' ? true : this.displayNavButtons = typeof this.displayNavButtons == 'undefined' ? true :
this.utils.isTrueOrOne(this.displayNavButtons); this.utils.isTrueOrOne(this.displayNavButtons);
}
if ((changes.courseId || changes.categoryId) && this.weeks) { /**
this.filterEvents(); * Detect and act upon changes that Angular cant or wont detect on its own (objects and arrays).
*/
ngDoCheck(): void {
if (this.weeks) {
// Check if there's any change in the filter object.
const changes = this.differ.diff(this.filter);
if (changes) {
this.filterEvents();
}
} }
} }
@ -260,21 +273,12 @@ export class AddonCalendarCalendarComponent implements OnInit, OnChanges, OnDest
} }
/** /**
* Filter events to only display events belonging to a certain course. * Filter events based on the filter popover.
*/ */
filterEvents(): void { filterEvents(): void {
const courseId = this.courseId ? Number(this.courseId) : undefined,
categoryId = this.categoryId ? Number(this.categoryId) : undefined;
this.weeks.forEach((week) => { this.weeks.forEach((week) => {
week.days.forEach((day) => { week.days.forEach((day) => {
if (!courseId || courseId < 0) { day.filteredEvents = this.calendarHelper.getFilteredEvents(day.events, this.filter, this.categories);
day.filteredEvents = day.events;
} else {
day.filteredEvents = day.events.filter((event) => {
return this.calendarHelper.shouldDisplayEvent(event, courseId, categoryId, this.categories);
});
}
// Re-calculate some properties. // Re-calculate some properties.
this.calendarHelper.calculateDayData(day, day.filteredEvents); this.calendarHelper.calculateDayData(day, day.filteredEvents);

View File

@ -21,11 +21,13 @@ import { CoreDirectivesModule } from '@directives/directives.module';
import { CorePipesModule } from '@pipes/pipes.module'; import { CorePipesModule } from '@pipes/pipes.module';
import { AddonCalendarCalendarComponent } from '../components/calendar/calendar'; import { AddonCalendarCalendarComponent } from '../components/calendar/calendar';
import { AddonCalendarUpcomingEventsComponent } from '../components/upcoming-events/upcoming-events'; import { AddonCalendarUpcomingEventsComponent } from '../components/upcoming-events/upcoming-events';
import { AddonCalendarFilterPopoverComponent } from '../components/filter/filter';
@NgModule({ @NgModule({
declarations: [ declarations: [
AddonCalendarCalendarComponent, AddonCalendarCalendarComponent,
AddonCalendarUpcomingEventsComponent AddonCalendarUpcomingEventsComponent,
AddonCalendarFilterPopoverComponent
], ],
imports: [ imports: [
CommonModule, CommonModule,
@ -39,7 +41,11 @@ import { AddonCalendarUpcomingEventsComponent } from '../components/upcoming-eve
], ],
exports: [ exports: [
AddonCalendarCalendarComponent, AddonCalendarCalendarComponent,
AddonCalendarUpcomingEventsComponent AddonCalendarUpcomingEventsComponent,
AddonCalendarFilterPopoverComponent
],
entryComponents: [
AddonCalendarFilterPopoverComponent
] ]
}) })
export class AddonCalendarComponentsModule {} export class AddonCalendarComponentsModule {}

View File

@ -0,0 +1,14 @@
<ion-list radio-group>
<ion-item *ngFor="let type of typeKeys" class="addon-calendar-event" [ngClass]="['addon-calendar-eventtype-'+type]">
<core-icon [name]="typeIcons[type]" item-start></core-icon>
<ion-label>{{ 'addon.calendar.' + type + 'events' | translate}}</ion-label>
<ion-toggle [(ngModel)]="types[type]" (ionChange)="onChange($event)"></ion-toggle>
</ion-item>
<ion-item-divider></ion-item-divider>
<ion-list radio-group [(ngModel)]="courseId" *ngIf="types.course || types.category || types.group">
<ion-item text-wrap *ngFor="let course of courses" >
<ion-label><core-format-text [text]="course.fullname"></core-format-text></ion-label>
<ion-radio value="{{course.id}}" (ionSelect)="onChange($event)" ></ion-radio>
</ion-item>
</ion-list>
</ion-list>

View File

@ -0,0 +1,69 @@
// (C) Copyright 2015 Martin Dougiamas
//
// 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 { Component } from '@angular/core';
import { NavParams } from 'ionic-angular';
import { CoreEventsProvider } from '@providers/events';
import { AddonCalendarProvider } from '../../providers/calendar';
import { AddonCalendarHelperProvider } from '../../providers/helper';
/**
* Component to display a list of courses.
*/
@Component({
selector: 'addon-calendar-filter-popover',
templateUrl: 'addon-calendar-filter-popover.html'
})
export class AddonCalendarFilterPopoverComponent {
courses: any[];
courseId = -1;
types = {};
typeIcons = {};
typeKeys = [];
constructor(navParams: NavParams, protected eventsProvider: CoreEventsProvider) {
this.courses = navParams.get('courses') || [];
const filter = navParams.get('filter') || {};
this.courseId = filter.courseId || -1;
this.typeKeys = AddonCalendarProvider.ALL_TYPES.map((name) => {
this.types[name] = filter[name];
this.typeIcons[name] = AddonCalendarHelperProvider.EVENTICONS[name];
return name;
});
}
/**
* Function called when an item is clicked.
*
* @param event Click event.
*/
onChange(event: Event): void {
const filter = this.types;
if (this.courseId > 0) {
const course = this.courses.find((course) => this.courseId == course.id);
filter['courseId'] = course && course.id;
filter['categoryId'] = course && course.category;
} else {
filter['courseId'] = false;
filter['categoryId'] = false;
}
filter['filtered'] = filter['courseId'] || AddonCalendarProvider.ALL_TYPES.some((name) => !this.types[name]);
this.eventsProvider.trigger(AddonCalendarProvider.FILTER_CHANGED_EVENT, filter);
}
}

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
import { Component, OnDestroy, OnInit, Input, OnChanges, SimpleChange, Output, EventEmitter } from '@angular/core'; import { Component, OnDestroy, OnInit, Input, DoCheck, Output, EventEmitter, KeyValueDiffers } from '@angular/core';
import { CoreEventsProvider } from '@providers/events'; import { CoreEventsProvider } from '@providers/events';
import { CoreLocalNotificationsProvider } from '@providers/local-notifications'; import { CoreLocalNotificationsProvider } from '@providers/local-notifications';
import { CoreSitesProvider } from '@providers/sites'; import { CoreSitesProvider } from '@providers/sites';
@ -30,9 +30,8 @@ import { CoreConstants } from '@core/constants';
selector: 'addon-calendar-upcoming-events', selector: 'addon-calendar-upcoming-events',
templateUrl: 'addon-calendar-upcoming-events.html', templateUrl: 'addon-calendar-upcoming-events.html',
}) })
export class AddonCalendarUpcomingEventsComponent implements OnInit, OnChanges, OnDestroy { export class AddonCalendarUpcomingEventsComponent implements OnInit, DoCheck, OnDestroy {
@Input() courseId: number | string; @Input() filter: any; // Filter to apply.
@Input() categoryId: number | string; // Category ID the course belongs to.
@Output() onEventClicked = new EventEmitter<number>(); @Output() onEventClicked = new EventEmitter<number>();
filteredEvents = []; filteredEvents = [];
@ -49,6 +48,7 @@ export class AddonCalendarUpcomingEventsComponent implements OnInit, OnChanges,
protected deletedEvents = []; // Events deleted in offline. protected deletedEvents = []; // Events deleted in offline.
protected lookAhead: number; protected lookAhead: number;
protected timeFormat: string; protected timeFormat: string;
protected differ: any; // To detect changes in the data input.
// Observers. // Observers.
protected undeleteEventObserver: any; protected undeleteEventObserver: any;
@ -57,6 +57,7 @@ export class AddonCalendarUpcomingEventsComponent implements OnInit, OnChanges,
constructor(eventsProvider: CoreEventsProvider, constructor(eventsProvider: CoreEventsProvider,
sitesProvider: CoreSitesProvider, sitesProvider: CoreSitesProvider,
localNotificationsProvider: CoreLocalNotificationsProvider, localNotificationsProvider: CoreLocalNotificationsProvider,
differs: KeyValueDiffers,
private calendarProvider: AddonCalendarProvider, private calendarProvider: AddonCalendarProvider,
private calendarHelper: AddonCalendarHelperProvider, private calendarHelper: AddonCalendarHelperProvider,
private calendarOffline: AddonCalendarOfflineProvider, private calendarOffline: AddonCalendarOfflineProvider,
@ -85,6 +86,8 @@ export class AddonCalendarUpcomingEventsComponent implements OnInit, OnChanges,
} }
} }
}, this.currentSiteId); }, this.currentSiteId);
this.differ = differs.find([]).create();
} }
/** /**
@ -95,10 +98,12 @@ export class AddonCalendarUpcomingEventsComponent implements OnInit, OnChanges,
} }
/** /**
* Detect changes on input properties. * Detect and act upon changes that Angular cant or wont detect on its own (objects and arrays).
*/ */
ngOnChanges(changes: {[name: string]: SimpleChange}): void { ngDoCheck(): void {
if (changes.courseId || changes.categoryId) { // Check if there's any change in the filter object.
const changes = this.differ.diff(this.filter);
if (changes) {
this.filterEvents(); this.filterEvents();
} }
} }
@ -207,19 +212,10 @@ export class AddonCalendarUpcomingEventsComponent implements OnInit, OnChanges,
} }
/** /**
* Filter events to only display events belonging to a certain course. * Filter events based on the filter popover.
*/ */
filterEvents(): void { protected filterEvents(): void {
const courseId = this.courseId ? Number(this.courseId) : undefined, this.filteredEvents = this.calendarHelper.getFilteredEvents(this.events, this.filter, this.categories);
categoryId = this.categoryId ? Number(this.categoryId) : undefined;
if (!courseId || courseId < 0) {
this.filteredEvents = this.events;
} else {
this.filteredEvents = this.events.filter((event) => {
return this.calendarHelper.shouldDisplayEvent(event, courseId, categoryId, this.categories);
});
}
} }
/** /**

View File

@ -4,8 +4,10 @@
"calendarevent": "Calendar event", "calendarevent": "Calendar event",
"calendarevents": "Calendar events", "calendarevents": "Calendar events",
"calendarreminders": "Calendar reminders", "calendarreminders": "Calendar reminders",
"categoryevents": "Category events",
"confirmeventdelete": "Are you sure you want to delete the \"{{$a}}\" event?", "confirmeventdelete": "Are you sure you want to delete the \"{{$a}}\" event?",
"confirmeventseriesdelete": "The \"{{$a.name}}\" event is part of a series. Do you want to delete just this event, or all {{$a.count}} events in the series?", "confirmeventseriesdelete": "The \"{{$a.name}}\" event is part of a series. Do you want to delete just this event, or all {{$a.count}} events in the series?",
"courseevents": "Course events",
"currentmonth": "Current Month", "currentmonth": "Current Month",
"daynext": "Next day", "daynext": "Next day",
"dayprev": "Previous day", "dayprev": "Previous day",
@ -29,6 +31,7 @@
"fri": "Fri", "fri": "Fri",
"friday": "Friday", "friday": "Friday",
"gotoactivity": "Go to activity", "gotoactivity": "Go to activity",
"groupevents": "Group events",
"invalidtimedurationminutes": "The duration in minutes you have entered is invalid. Please enter the duration in minutes greater than 0 or select no duration.", "invalidtimedurationminutes": "The duration in minutes you have entered is invalid. Please enter the duration in minutes greater than 0 or select no duration.",
"invalidtimedurationuntil": "The date and time you selected for duration until is before the start time of the event. Please correct this before proceeding.", "invalidtimedurationuntil": "The date and time you selected for duration until is before the start time of the event. Please correct this before proceeding.",
"mon": "Mon", "mon": "Mon",
@ -46,6 +49,7 @@
"sat": "Sat", "sat": "Sat",
"saturday": "Saturday", "saturday": "Saturday",
"setnewreminder": "Set a new reminder", "setnewreminder": "Set a new reminder",
"siteevents": "Site events",
"sun": "Sun", "sun": "Sun",
"sunday": "Sunday", "sunday": "Sunday",
"thu": "Thu", "thu": "Thu",
@ -64,6 +68,7 @@
"typesite": "Site event", "typesite": "Site event",
"typeuser": "User event", "typeuser": "User event",
"upcomingevents": "Upcoming events", "upcomingevents": "Upcoming events",
"userevents": "User events",
"wed": "Wed", "wed": "Wed",
"wednesday": "Wednesday", "wednesday": "Wednesday",
"when": "When", "when": "When",

View File

@ -2,9 +2,9 @@
<ion-navbar core-back-button> <ion-navbar core-back-button>
<ion-title>{{ 'addon.calendar.calendarevents' | translate }}</ion-title> <ion-title>{{ 'addon.calendar.calendarevents' | translate }}</ion-title>
<ion-buttons end> <ion-buttons end>
<button *ngIf="courses && courses.length" ion-button icon-only (click)="openCourseFilter($event)" [attr.aria-label]="'core.courses.filter' | translate"> <button ion-button icon-only (click)="openFilter($event)" [attr.aria-label]="'core.filter' | translate">
<ion-icon name="funnel" *ngIf="courseId"></ion-icon> <ion-icon name="funnel" *ngIf="filter.filtered"></ion-icon>
<ion-icon name="ios-funnel-outline" *ngIf="!courseId"></ion-icon> <ion-icon name="ios-funnel-outline" *ngIf="!filter.filtered"></ion-icon>
</button> </button>
<core-context-menu> <core-context-menu>
<core-context-menu-item *ngIf="!isCurrentDay" [priority]="900" [content]="'addon.calendar.today' | translate" [iconAction]="'fa-calendar-times-o'" (action)="goToCurrentDay()"></core-context-menu-item> <core-context-menu-item *ngIf="!isCurrentDay" [priority]="900" [content]="'addon.calendar.today' | translate" [iconAction]="'fa-calendar-times-o'" (action)="goToCurrentDay()"></core-context-menu-item>

View File

@ -13,7 +13,7 @@
// limitations under the License. // limitations under the License.
import { Component, OnInit, OnDestroy, NgZone } from '@angular/core'; import { Component, OnInit, OnDestroy, NgZone } from '@angular/core';
import { IonicPage, NavParams, NavController } from 'ionic-angular'; import { IonicPage, NavParams, NavController, PopoverController } from 'ionic-angular';
import { CoreAppProvider } from '@providers/app'; import { CoreAppProvider } from '@providers/app';
import { CoreEventsProvider } from '@providers/events'; import { CoreEventsProvider } from '@providers/events';
import { CoreLocalNotificationsProvider } from '@providers/local-notifications'; import { CoreLocalNotificationsProvider } from '@providers/local-notifications';
@ -26,6 +26,7 @@ import { AddonCalendarHelperProvider } from '../../providers/helper';
import { AddonCalendarSyncProvider } from '../../providers/calendar-sync'; import { AddonCalendarSyncProvider } from '../../providers/calendar-sync';
import { CoreCoursesProvider } from '@core/courses/providers/courses'; import { CoreCoursesProvider } from '@core/courses/providers/courses';
import { CoreCoursesHelperProvider } from '@core/courses/providers/helper'; import { CoreCoursesHelperProvider } from '@core/courses/providers/helper';
import { AddonCalendarFilterPopoverComponent } from '../../components/filter/filter';
import { Network } from '@ionic-native/network'; import { Network } from '@ionic-native/network';
import * as moment from 'moment'; import * as moment from 'moment';
@ -63,11 +64,10 @@ export class AddonCalendarDayPage implements OnInit, OnDestroy {
protected manualSyncObserver: any; protected manualSyncObserver: any;
protected onlineObserver: any; protected onlineObserver: any;
protected obsDefaultTimeChange: any; protected obsDefaultTimeChange: any;
protected filterChangedObserver: any;
periodName: string; periodName: string;
filteredEvents = []; filteredEvents = [];
courseId: number;
categoryId: number;
canCreate = false; canCreate = false;
courses: any[]; courses: any[];
loaded = false; loaded = false;
@ -76,6 +76,7 @@ export class AddonCalendarDayPage implements OnInit, OnDestroy {
syncIcon: string; syncIcon: string;
isCurrentDay: boolean; isCurrentDay: boolean;
isPastDay: boolean; isPastDay: boolean;
filter = {};
constructor(localNotificationsProvider: CoreLocalNotificationsProvider, constructor(localNotificationsProvider: CoreLocalNotificationsProvider,
navParams: NavParams, navParams: NavParams,
@ -92,14 +93,19 @@ export class AddonCalendarDayPage implements OnInit, OnDestroy {
private eventsProvider: CoreEventsProvider, private eventsProvider: CoreEventsProvider,
private coursesProvider: CoreCoursesProvider, private coursesProvider: CoreCoursesProvider,
private coursesHelper: CoreCoursesHelperProvider, private coursesHelper: CoreCoursesHelperProvider,
private appProvider: CoreAppProvider) { private appProvider: CoreAppProvider,
private popoverCtrl: PopoverController) {
const now = new Date(); const now = new Date();
AddonCalendarProvider.ALL_TYPES.forEach((name) => {
this.filter[name] = true;
});
this.filter['courseId'] = navParams.get('courseId');
this.year = navParams.get('year') || now.getFullYear(); this.year = navParams.get('year') || now.getFullYear();
this.month = navParams.get('month') || (now.getMonth() + 1); this.month = navParams.get('month') || (now.getMonth() + 1);
this.day = navParams.get('day') || now.getDate(); this.day = navParams.get('day') || now.getDate();
this.courseId = navParams.get('courseId');
this.currentSiteId = sitesProvider.getCurrentSiteId(); this.currentSiteId = sitesProvider.getCurrentSiteId();
if (localNotificationsProvider.isAvailable()) { if (localNotificationsProvider.isAvailable()) {
@ -186,6 +192,17 @@ export class AddonCalendarDayPage implements OnInit, OnDestroy {
} }
}, this.currentSiteId); }, this.currentSiteId);
this.filterChangedObserver = this.eventsProvider.on(AddonCalendarProvider.FILTER_CHANGED_EVENT, (data) => {
this.filter = data;
// Course viewed has changed, check if the user can create events for this course calendar.
this.calendarHelper.canEditEvents(this.filter['courseId']).then((canEdit) => {
this.canCreate = canEdit;
});
this.filterEvents();
});
// Refresh online status when changes. // Refresh online status when changes.
this.onlineObserver = network.onchange().subscribe(() => { this.onlineObserver = network.onchange().subscribe(() => {
// Execute the callback in the Angular zone, so change detection doesn't stop working. // Execute the callback in the Angular zone, so change detection doesn't stop working.
@ -223,9 +240,8 @@ export class AddonCalendarDayPage implements OnInit, OnDestroy {
const promises = []; const promises = [];
// Load courses for the popover. // Load courses for the popover.
promises.push(this.coursesHelper.getCoursesForPopover(this.courseId).then((data) => { promises.push(this.coursesHelper.getCoursesForPopover(this.filter['courseId']).then((data) => {
this.courses = data.courses; this.courses = data.courses;
this.categoryId = data.categoryId;
})); }));
// Get categories. // Get categories.
@ -257,7 +273,7 @@ export class AddonCalendarDayPage implements OnInit, OnDestroy {
})); }));
// Check if user can create events. // Check if user can create events.
promises.push(this.calendarHelper.canEditEvents(this.courseId).then((canEdit) => { promises.push(this.calendarHelper.canEditEvents(this.filter['courseId']).then((canEdit) => {
this.canCreate = canEdit; this.canCreate = canEdit;
})); }));
@ -374,16 +390,10 @@ export class AddonCalendarDayPage implements OnInit, OnDestroy {
} }
/** /**
* Filter events to only display events belonging to a certain course. * Filter events based on the filter popover.
*/ */
protected filterEvents(): void { protected filterEvents(): void {
if (!this.courseId || this.courseId < 0) { this.filteredEvents = this.calendarHelper.getFilteredEvents(this.events, this.filter, this.categories);
this.filteredEvents = this.events;
} else {
this.filteredEvents = this.events.filter((event) => {
return this.calendarHelper.shouldDisplayEvent(event, this.courseId, this.categoryId, this.categories);
});
}
} }
/** /**
@ -513,19 +523,14 @@ export class AddonCalendarDayPage implements OnInit, OnDestroy {
* *
* @param event Event. * @param event Event.
*/ */
openCourseFilter(event: MouseEvent): void { openFilter(event: MouseEvent): void {
this.coursesHelper.selectCourse(event, this.courses, this.courseId).then((result) => { const popover = this.popoverCtrl.create(AddonCalendarFilterPopoverComponent, {
if (typeof result.courseId != 'undefined') { courses: this.courses,
this.courseId = result.courseId > 0 ? result.courseId : undefined; filter: this.filter
this.categoryId = result.courseId > 0 ? result.categoryId : undefined; });
// Course viewed has changed, check if the user can create events for this course calendar. popover.present({
this.calendarHelper.canEditEvents(this.courseId).then((canEdit) => { ev: event
this.canCreate = canEdit;
});
this.filterEvents();
}
}); });
} }
@ -544,8 +549,8 @@ export class AddonCalendarDayPage implements OnInit, OnDestroy {
params.timestamp = moment().year(this.year).month(this.month - 1).date(this.day).unix() * 1000; params.timestamp = moment().year(this.year).month(this.month - 1).date(this.day).unix() * 1000;
} }
if (this.courseId) { if (this.filter['courseId']) {
params.courseId = this.courseId; params.courseId = this.filter['courseId'];
} }
this.navCtrl.push('AddonCalendarEditEventPage', params); this.navCtrl.push('AddonCalendarEditEventPage', params);
@ -697,6 +702,7 @@ export class AddonCalendarDayPage implements OnInit, OnDestroy {
this.syncObserver && this.syncObserver.off(); this.syncObserver && this.syncObserver.off();
this.manualSyncObserver && this.manualSyncObserver.off(); this.manualSyncObserver && this.manualSyncObserver.off();
this.onlineObserver && this.onlineObserver.unsubscribe(); this.onlineObserver && this.onlineObserver.unsubscribe();
this.filterChangedObserver && this.filterChangedObserver.off();
this.obsDefaultTimeChange && this.obsDefaultTimeChange.off(); this.obsDefaultTimeChange && this.obsDefaultTimeChange.off();
} }
} }

View File

@ -2,9 +2,9 @@
<ion-navbar core-back-button> <ion-navbar core-back-button>
<ion-title>{{ (showCalendar ? 'addon.calendar.calendarevents' : 'addon.calendar.upcomingevents') | translate }}</ion-title> <ion-title>{{ (showCalendar ? 'addon.calendar.calendarevents' : 'addon.calendar.upcomingevents') | translate }}</ion-title>
<ion-buttons end> <ion-buttons end>
<button *ngIf="courses && courses.length" ion-button icon-only (click)="openCourseFilter($event)" [attr.aria-label]="'core.courses.filter' | translate"> <button ion-button icon-only (click)="openFilter($event)" [attr.aria-label]="'core.filter' | translate">
<ion-icon name="funnel" *ngIf="courseId"></ion-icon> <ion-icon name="funnel" *ngIf="filter.filtered"></ion-icon>
<ion-icon name="ios-funnel-outline" *ngIf="!courseId"></ion-icon> <ion-icon name="ios-funnel-outline" *ngIf="!filter.filtered"></ion-icon>
</button> </button>
<core-context-menu> <core-context-menu>
<core-context-menu-item *ngIf="showCalendar" [priority]="800" [content]="'addon.calendar.upcomingevents' | translate" [iconAction]="'list'" (action)="toggleDisplay()"></core-context-menu-item> <core-context-menu-item *ngIf="showCalendar" [priority]="800" [content]="'addon.calendar.upcomingevents' | translate" [iconAction]="'list'" (action)="toggleDisplay()"></core-context-menu-item>
@ -25,9 +25,9 @@
<ion-icon name="warning"></ion-icon> {{ 'core.hasdatatosync' | translate:{$a: 'addon.calendar.calendar' | translate} }} <ion-icon name="warning"></ion-icon> {{ 'core.hasdatatosync' | translate:{$a: 'addon.calendar.calendar' | translate} }}
</ion-card> </ion-card>
<addon-calendar-calendar [hidden]="!showCalendar" [initialYear]="year" [initialMonth]="month" [courseId]="courseId" [categoryId]="categoryId" [displayNavButtons]="showCalendar" (onEventClicked)="gotoEvent($event)" (onDayClicked)="gotoDay($event)"></addon-calendar-calendar> <addon-calendar-calendar [hidden]="!showCalendar" [initialYear]="year" [initialMonth]="month" [filter]="filter" [displayNavButtons]="showCalendar" (onEventClicked)="gotoEvent($event)" (onDayClicked)="gotoDay($event)"></addon-calendar-calendar>
<addon-calendar-upcoming-events *ngIf="loadUpcoming" [hidden]="showCalendar" [courseId]="courseId" [categoryId]="categoryId" (onEventClicked)="gotoEvent($event)"></addon-calendar-upcoming-events> <addon-calendar-upcoming-events *ngIf="loadUpcoming" [hidden]="showCalendar" [filter]="filter" (onEventClicked)="gotoEvent($event)"></addon-calendar-upcoming-events>
<!-- Create a calendar event. --> <!-- Create a calendar event. -->
<ion-fab core-fab bottom end *ngIf="canCreate"> <ion-fab core-fab bottom end *ngIf="canCreate">

View File

@ -13,7 +13,7 @@
// limitations under the License. // limitations under the License.
import { Component, OnInit, OnDestroy, ViewChild, NgZone } from '@angular/core'; import { Component, OnInit, OnDestroy, ViewChild, NgZone } from '@angular/core';
import { IonicPage, NavParams, NavController } from 'ionic-angular'; import { IonicPage, NavParams, NavController, PopoverController } from 'ionic-angular';
import { CoreAppProvider } from '@providers/app'; import { CoreAppProvider } from '@providers/app';
import { CoreEventsProvider } from '@providers/events'; import { CoreEventsProvider } from '@providers/events';
import { CoreLocalNotificationsProvider } from '@providers/local-notifications'; import { CoreLocalNotificationsProvider } from '@providers/local-notifications';
@ -24,6 +24,7 @@ import { AddonCalendarOfflineProvider } from '../../providers/calendar-offline';
import { AddonCalendarHelperProvider } from '../../providers/helper'; import { AddonCalendarHelperProvider } from '../../providers/helper';
import { AddonCalendarCalendarComponent } from '../../components/calendar/calendar'; import { AddonCalendarCalendarComponent } from '../../components/calendar/calendar';
import { AddonCalendarUpcomingEventsComponent } from '../../components/upcoming-events/upcoming-events'; import { AddonCalendarUpcomingEventsComponent } from '../../components/upcoming-events/upcoming-events';
import { AddonCalendarFilterPopoverComponent } from '../../components/filter/filter';
import { AddonCalendarSyncProvider } from '../../providers/calendar-sync'; import { AddonCalendarSyncProvider } from '../../providers/calendar-sync';
import { CoreCoursesHelperProvider } from '@core/courses/providers/helper'; import { CoreCoursesHelperProvider } from '@core/courses/providers/helper';
import { Network } from '@ionic-native/network'; import { Network } from '@ionic-native/network';
@ -52,11 +53,10 @@ export class AddonCalendarIndexPage implements OnInit, OnDestroy {
protected syncObserver: any; protected syncObserver: any;
protected manualSyncObserver: any; protected manualSyncObserver: any;
protected onlineObserver: any; protected onlineObserver: any;
protected filterChangedObserver: any;
year: number; year: number;
month: number; month: number;
courseId: number;
categoryId: number;
canCreate = false; canCreate = false;
courses: any[]; courses: any[];
notificationsEnabled = false; notificationsEnabled = false;
@ -66,6 +66,7 @@ export class AddonCalendarIndexPage implements OnInit, OnDestroy {
syncIcon: string; syncIcon: string;
showCalendar = true; showCalendar = true;
loadUpcoming = false; loadUpcoming = false;
filter = {};
constructor(localNotificationsProvider: CoreLocalNotificationsProvider, constructor(localNotificationsProvider: CoreLocalNotificationsProvider,
navParams: NavParams, navParams: NavParams,
@ -80,9 +81,9 @@ export class AddonCalendarIndexPage implements OnInit, OnDestroy {
private calendarSync: AddonCalendarSyncProvider, private calendarSync: AddonCalendarSyncProvider,
private eventsProvider: CoreEventsProvider, private eventsProvider: CoreEventsProvider,
private coursesHelper: CoreCoursesHelperProvider, private coursesHelper: CoreCoursesHelperProvider,
private appProvider: CoreAppProvider) { private appProvider: CoreAppProvider,
private popoverCtrl: PopoverController) {
this.courseId = navParams.get('courseId');
this.eventId = navParams.get('eventId') || false; this.eventId = navParams.get('eventId') || false;
this.year = navParams.get('year'); this.year = navParams.get('year');
this.month = navParams.get('month'); this.month = navParams.get('month');
@ -91,6 +92,11 @@ export class AddonCalendarIndexPage implements OnInit, OnDestroy {
this.loadUpcoming = !!navParams.get('upcoming'); this.loadUpcoming = !!navParams.get('upcoming');
this.showCalendar = !this.loadUpcoming; this.showCalendar = !this.loadUpcoming;
AddonCalendarProvider.ALL_TYPES.forEach((name) => {
this.filter[name] = true;
});
this.filter['courseId'] = navParams.get('courseId');
// 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 = eventsProvider.on(AddonCalendarProvider.NEW_EVENT_EVENT, (data) => { this.newEventObserver = eventsProvider.on(AddonCalendarProvider.NEW_EVENT_EVENT, (data) => {
if (data && data.event) { if (data && data.event) {
@ -140,6 +146,15 @@ export class AddonCalendarIndexPage implements OnInit, OnDestroy {
}); });
}, this.currentSiteId); }, this.currentSiteId);
this.filterChangedObserver = this.eventsProvider.on(AddonCalendarProvider.FILTER_CHANGED_EVENT, (data) => {
this.filter = data;
// Course viewed has changed, check if the user can create events for this course calendar.
this.calendarHelper.canEditEvents(this.filter['courseId']).then((canEdit) => {
this.canCreate = canEdit;
});
});
// Refresh online status when changes. // Refresh online status when changes.
this.onlineObserver = network.onchange().subscribe(() => { this.onlineObserver = network.onchange().subscribe(() => {
// Execute the callback in the Angular zone, so change detection doesn't stop working. // Execute the callback in the Angular zone, so change detection doesn't stop working.
@ -203,13 +218,12 @@ export class AddonCalendarIndexPage implements OnInit, OnDestroy {
this.hasOffline = false; this.hasOffline = false;
// Load courses for the popover. // Load courses for the popover.
promises.push(this.coursesHelper.getCoursesForPopover(this.courseId).then((data) => { promises.push(this.coursesHelper.getCoursesForPopover(this.filter['courseId']).then((data) => {
this.courses = data.courses; this.courses = data.courses;
this.categoryId = data.categoryId;
})); }));
// Check if user can create events. // Check if user can create events.
promises.push(this.calendarHelper.canEditEvents(this.courseId).then((canEdit) => { promises.push(this.calendarHelper.canEditEvents(this.filter['courseId']).then((canEdit) => {
this.canCreate = canEdit; this.canCreate = canEdit;
})); }));
@ -301,8 +315,8 @@ export class AddonCalendarIndexPage implements OnInit, OnDestroy {
year: data.year year: data.year
}; };
if (this.courseId) { if (this.filter['courseId']) {
params.courseId = this.courseId; params.courseId = this.filter['courseId'];
} }
this.navCtrl.push('AddonCalendarDayPage', params); this.navCtrl.push('AddonCalendarDayPage', params);
@ -313,17 +327,14 @@ export class AddonCalendarIndexPage implements OnInit, OnDestroy {
* *
* @param event Event. * @param event Event.
*/ */
openCourseFilter(event: MouseEvent): void { openFilter(event: MouseEvent): void {
this.coursesHelper.selectCourse(event, this.courses, this.courseId).then((result) => { const popover = this.popoverCtrl.create(AddonCalendarFilterPopoverComponent, {
if (typeof result.courseId != 'undefined') { courses: this.courses,
this.courseId = result.courseId > 0 ? result.courseId : undefined; filter: this.filter
this.categoryId = result.courseId > 0 ? result.categoryId : undefined; });
// Course viewed has changed, check if the user can create events for this course calendar. popover.present({
this.calendarHelper.canEditEvents(this.courseId).then((canEdit) => { ev: event
this.canCreate = canEdit;
});
}
}); });
} }
@ -338,8 +349,8 @@ export class AddonCalendarIndexPage implements OnInit, OnDestroy {
if (eventId) { if (eventId) {
params.eventId = eventId; params.eventId = eventId;
} }
if (this.courseId) { if (this.filter['courseId']) {
params.courseId = this.courseId; params.courseId = this.filter['courseId'];
} }
this.navCtrl.push('AddonCalendarEditEventPage', params); this.navCtrl.push('AddonCalendarEditEventPage', params);
@ -374,6 +385,7 @@ export class AddonCalendarIndexPage implements OnInit, OnDestroy {
this.undeleteEventObserver && this.undeleteEventObserver.off(); this.undeleteEventObserver && this.undeleteEventObserver.off();
this.syncObserver && this.syncObserver.off(); this.syncObserver && this.syncObserver.off();
this.manualSyncObserver && this.manualSyncObserver.off(); this.manualSyncObserver && this.manualSyncObserver.off();
this.filterChangedObserver && this.filterChangedObserver.off();
this.onlineObserver && this.onlineObserver.unsubscribe(); this.onlineObserver && this.onlineObserver.unsubscribe();
} }
} }

View File

@ -2,9 +2,9 @@
<ion-navbar core-back-button> <ion-navbar core-back-button>
<ion-title>{{ 'addon.calendar.calendarevents' | translate }}</ion-title> <ion-title>{{ 'addon.calendar.calendarevents' | translate }}</ion-title>
<ion-buttons end> <ion-buttons end>
<button *ngIf="courses && courses.length" ion-button icon-only (click)="openCourseFilter($event)" [attr.aria-label]="'core.courses.filter' | translate"> <button ion-button icon-only (click)="openFilter($event)" [attr.aria-label]="'core.filter' | translate">
<ion-icon name="funnel" *ngIf="courseId"></ion-icon> <ion-icon name="funnel" *ngIf="filter.filtered"></ion-icon>
<ion-icon name="ios-funnel-outline" *ngIf="!courseId"></ion-icon> <ion-icon name="ios-funnel-outline" *ngIf="!filter.filtered"></ion-icon>
</button> </button>
<core-context-menu> <core-context-menu>
<core-context-menu-item [hidden]="!notificationsEnabled" [priority]="600" [content]="'core.settings.settings' | translate" (action)="openSettings()" [iconAction]="'cog'"></core-context-menu-item> <core-context-menu-item [hidden]="!notificationsEnabled" [priority]="600" [content]="'core.settings.settings' | translate" (action)="openSettings()" [iconAction]="'cog'"></core-context-menu-item>

View File

@ -13,7 +13,7 @@
// limitations under the License. // limitations under the License.
import { Component, ViewChild, OnDestroy, NgZone } from '@angular/core'; import { Component, ViewChild, OnDestroy, NgZone } from '@angular/core';
import { IonicPage, Content, NavParams, NavController } from 'ionic-angular'; import { IonicPage, Content, NavParams, NavController, PopoverController } from 'ionic-angular';
import { AddonCalendarProvider, AddonCalendarGetEventsEvent } from '../../providers/calendar'; import { AddonCalendarProvider, AddonCalendarGetEventsEvent } from '../../providers/calendar';
import { AddonCalendarOfflineProvider } from '../../providers/calendar-offline'; import { AddonCalendarOfflineProvider } from '../../providers/calendar-offline';
import { AddonCalendarHelperProvider } from '../../providers/helper'; import { AddonCalendarHelperProvider } from '../../providers/helper';
@ -31,6 +31,7 @@ import { CoreSplitViewComponent } from '@components/split-view/split-view';
import * as moment from 'moment'; import * as moment from 'moment';
import { Network } from '@ionic-native/network'; import { Network } from '@ionic-native/network';
import { CoreConstants } from '@core/constants'; import { CoreConstants } from '@core/constants';
import { AddonCalendarFilterPopoverComponent } from '../../components/filter/filter';
/** /**
* Page that displays the list of calendar events. * Page that displays the list of calendar events.
@ -51,8 +52,14 @@ export class AddonCalendarListPage implements OnDestroy {
protected getCategories = false; protected getCategories = false;
protected categories = {}; protected categories = {};
protected siteHomeId: number; protected siteHomeId: number;
protected obsDefaultTimeChange: any;
protected eventId: number; protected eventId: number;
protected currentSiteId: string;
protected onlineEvents: AddonCalendarGetEventsEvent[] = [];
protected offlineEvents = [];
protected deletedEvents = [];
// Observers.
protected obsDefaultTimeChange: any;
protected newEventObserver: any; protected newEventObserver: any;
protected discardedObserver: any; protected discardedObserver: any;
protected editEventObserver: any; protected editEventObserver: any;
@ -61,10 +68,7 @@ export class AddonCalendarListPage implements OnDestroy {
protected syncObserver: any; protected syncObserver: any;
protected manualSyncObserver: any; protected manualSyncObserver: any;
protected onlineObserver: any; protected onlineObserver: any;
protected currentSiteId: string; protected filterChangedObserver: any;
protected onlineEvents: AddonCalendarGetEventsEvent[] = [];
protected offlineEvents = [];
protected deletedEvents = [];
courses: any[]; courses: any[];
eventsLoaded = false; eventsLoaded = false;
@ -73,20 +77,31 @@ export class AddonCalendarListPage implements OnDestroy {
filteredEvents: AddonCalendarGetEventsEvent[] = []; filteredEvents: AddonCalendarGetEventsEvent[] = [];
canLoadMore = false; canLoadMore = false;
loadMoreError = false; loadMoreError = false;
courseId: number;
categoryId: number;
canCreate = false; canCreate = false;
hasOffline = false; hasOffline = false;
isOnline = false; isOnline = false;
syncIcon: string; // Sync icon. syncIcon: string; // Sync icon.
filter = {};
constructor(private calendarProvider: AddonCalendarProvider, navParams: NavParams, constructor(
private domUtils: CoreDomUtilsProvider, private coursesProvider: CoreCoursesProvider, private utils: CoreUtilsProvider, navParams: NavParams,
private calendarHelper: AddonCalendarHelperProvider, sitesProvider: CoreSitesProvider, zone: NgZone, sitesProvider: CoreSitesProvider,
localNotificationsProvider: CoreLocalNotificationsProvider, private coursesHelper: CoreCoursesHelperProvider, network: Network,
private eventsProvider: CoreEventsProvider, private navCtrl: NavController, private appProvider: CoreAppProvider, zone: NgZone,
private calendarOffline: AddonCalendarOfflineProvider, private calendarSync: AddonCalendarSyncProvider, localNotificationsProvider: CoreLocalNotificationsProvider,
network: Network, private timeUtils: CoreTimeUtilsProvider) { private calendarProvider: AddonCalendarProvider,
private domUtils: CoreDomUtilsProvider,
private coursesProvider: CoreCoursesProvider,
private utils: CoreUtilsProvider,
private calendarHelper: AddonCalendarHelperProvider,
private coursesHelper: CoreCoursesHelperProvider,
private eventsProvider: CoreEventsProvider,
private navCtrl: NavController,
private appProvider: CoreAppProvider,
private calendarOffline: AddonCalendarOfflineProvider,
private calendarSync: AddonCalendarSyncProvider,
private timeUtils: CoreTimeUtilsProvider,
private popoverCtrl: PopoverController) {
this.siteHomeId = sitesProvider.getCurrentSite().getSiteHomeId(); this.siteHomeId = sitesProvider.getCurrentSite().getSiteHomeId();
this.notificationsEnabled = localNotificationsProvider.isAvailable(); this.notificationsEnabled = localNotificationsProvider.isAvailable();
@ -100,7 +115,11 @@ export class AddonCalendarListPage implements OnDestroy {
} }
this.eventId = navParams.get('eventId') || false; this.eventId = navParams.get('eventId') || false;
this.courseId = navParams.get('courseId');
AddonCalendarProvider.ALL_TYPES.forEach((name) => {
this.filter[name] = true;
});
this.filter['courseId'] = navParams.get('courseId');
// 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 = eventsProvider.on(AddonCalendarProvider.NEW_EVENT_EVENT, (data) => { this.newEventObserver = eventsProvider.on(AddonCalendarProvider.NEW_EVENT_EVENT, (data) => {
@ -198,6 +217,19 @@ export class AddonCalendarListPage implements OnDestroy {
} }
}, this.currentSiteId); }, this.currentSiteId);
this.filterChangedObserver = this.eventsProvider.on(AddonCalendarProvider.FILTER_CHANGED_EVENT, (data) => {
this.filter = data;
// Course viewed has changed, check if the user can create events for this course calendar.
this.calendarHelper.canEditEvents(this.filter['courseId']).then((canEdit) => {
this.canCreate = canEdit;
});
this.filterEvents();
this.domUtils.scrollToTop(this.content);
});
// Refresh online status when changes. // Refresh online status when changes.
this.onlineObserver = network.onchange().subscribe(() => { this.onlineObserver = network.onchange().subscribe(() => {
// Execute the callback in the Angular zone, so change detection doesn't stop working. // Execute the callback in the Angular zone, so change detection doesn't stop working.
@ -274,14 +306,13 @@ export class AddonCalendarListPage implements OnDestroy {
this.hasOffline = false; this.hasOffline = false;
promises.push(this.calendarHelper.canEditEvents(this.courseId).then((canEdit) => { promises.push(this.calendarHelper.canEditEvents(this.filter['courseId']).then((canEdit) => {
this.canCreate = canEdit; this.canCreate = canEdit;
})); }));
// Load courses for the popover. // Load courses for the popover.
promises.push(this.coursesHelper.getCoursesForPopover(this.courseId).then((result) => { promises.push(this.coursesHelper.getCoursesForPopover(this.filter['courseId']).then((result) => {
this.courses = result.courses; this.courses = result.courses;
this.categoryId = result.categoryId;
return this.fetchEvents(refresh); return this.fetchEvents(refresh);
})); }));
@ -354,7 +385,7 @@ export class AddonCalendarListPage implements OnDestroy {
this.onlineEvents = this.utils.mergeArraysWithoutDuplicates(this.onlineEvents, onlineEvents, 'id'); this.onlineEvents = this.utils.mergeArraysWithoutDuplicates(this.onlineEvents, onlineEvents, 'id');
this.events = this.utils.mergeArraysWithoutDuplicates(this.events, events, 'id'); this.events = this.utils.mergeArraysWithoutDuplicates(this.events, events, 'id');
} }
this.filteredEvents = this.getFilteredEvents(); this.filterEvents();
// Calculate which evemts need to display the date. // Calculate which evemts need to display the date.
this.filteredEvents.forEach((event, index): any => { this.filteredEvents.forEach((event, index): any => {
@ -398,19 +429,9 @@ export class AddonCalendarListPage implements OnDestroy {
} }
/** /**
* Get filtered events.
*
* @return Filtered events.
*/ */
protected getFilteredEvents(): AddonCalendarGetEventsEvent[] { protected filterEvents(): void {
if (!this.courseId) { this.filteredEvents = this.calendarHelper.getFilteredEvents(this.events, this.filter, this.categories);
// No filter, display everything.
return this.events;
}
return this.events.filter((event) => {
return this.calendarHelper.shouldDisplayEvent(event, this.courseId, this.categoryId, this.categories);
});
} }
/** /**
@ -596,21 +617,14 @@ export class AddonCalendarListPage implements OnDestroy {
* *
* @param event Event. * @param event Event.
*/ */
openCourseFilter(event: MouseEvent): void { openFilter(event: MouseEvent): void {
this.coursesHelper.selectCourse(event, this.courses, this.courseId).then((result) => { const popover = this.popoverCtrl.create(AddonCalendarFilterPopoverComponent, {
if (typeof result.courseId != 'undefined') { courses: this.courses,
this.courseId = result.courseId > 0 ? result.courseId : undefined; filter: this.filter
this.categoryId = result.courseId > 0 ? result.categoryId : undefined; });
// Course viewed has changed, check if the user can create events for this course calendar. popover.present({
this.calendarHelper.canEditEvents(this.courseId).then((canEdit) => { ev: event
this.canCreate = canEdit;
});
this.filteredEvents = this.getFilteredEvents();
this.domUtils.scrollToTop(this.content);
}
}); });
} }
@ -627,8 +641,8 @@ export class AddonCalendarListPage implements OnDestroy {
if (eventId) { if (eventId) {
params.eventId = eventId; params.eventId = eventId;
} }
if (this.courseId) { if (this.filter['courseId']) {
params.courseId = this.courseId; params.courseId = this.filter['courseId'];
} }
this.splitviewCtrl.push('AddonCalendarEditEventPage', params); this.splitviewCtrl.push('AddonCalendarEditEventPage', params);
@ -687,6 +701,7 @@ export class AddonCalendarListPage implements OnDestroy {
this.undeleteEventObserver && this.undeleteEventObserver.off(); this.undeleteEventObserver && this.undeleteEventObserver.off();
this.syncObserver && this.syncObserver.off(); this.syncObserver && this.syncObserver.off();
this.manualSyncObserver && this.manualSyncObserver.off(); this.manualSyncObserver && this.manualSyncObserver.off();
this.filterChangedObserver && this.filterChangedObserver.off();
this.onlineObserver && this.onlineObserver.unsubscribe(); this.onlineObserver && this.onlineObserver.unsubscribe();
} }
} }

View File

@ -50,11 +50,17 @@ export class AddonCalendarProvider {
static EDIT_EVENT_EVENT = 'addon_calendar_edit_event'; static EDIT_EVENT_EVENT = 'addon_calendar_edit_event';
static DELETED_EVENT_EVENT = 'addon_calendar_deleted_event'; static DELETED_EVENT_EVENT = 'addon_calendar_deleted_event';
static UNDELETED_EVENT_EVENT = 'addon_calendar_undeleted_event'; static UNDELETED_EVENT_EVENT = 'addon_calendar_undeleted_event';
static FILTER_CHANGED_EVENT = 'addon_calendar_filter_changed_event';
static TYPE_CATEGORY = 'category'; static TYPE_CATEGORY = 'category';
static TYPE_COURSE = 'course'; static TYPE_COURSE = 'course';
static TYPE_GROUP = 'group'; static TYPE_GROUP = 'group';
static TYPE_SITE = 'site'; static TYPE_SITE = 'site';
static TYPE_USER = 'user'; static TYPE_USER = 'user';
static ALL_TYPES = [ AddonCalendarProvider.TYPE_SITE,
AddonCalendarProvider.TYPE_CATEGORY,
AddonCalendarProvider.TYPE_COURSE,
AddonCalendarProvider.TYPE_GROUP,
AddonCalendarProvider.TYPE_USER ];
static CALENDAR_TF_24 = '%H:%M'; // Calendar time in 24 hours format. static CALENDAR_TF_24 = '%H:%M'; // Calendar time in 24 hours format.
static CALENDAR_TF_12 = '%I:%M %p'; // Calendar time in 12 hours format. static CALENDAR_TF_12 = '%I:%M %p'; // Calendar time in 12 hours format.

View File

@ -29,8 +29,8 @@ import * as moment from 'moment';
export class AddonCalendarHelperProvider { export class AddonCalendarHelperProvider {
protected logger; protected logger;
protected EVENTICONS = { static EVENTICONS = {
course: 'fa-university', course: 'fa-graduation-cap',
group: 'people', group: 'people',
site: 'globe', site: 'globe',
user: 'person', user: 'person',
@ -131,7 +131,7 @@ export class AddonCalendarHelperProvider {
* @param e Event to format. * @param e Event to format.
*/ */
formatEventData(e: any): void { formatEventData(e: any): void {
e.eventIcon = this.EVENTICONS[e.eventtype] || ''; e.eventIcon = AddonCalendarHelperProvider.EVENTICONS[e.eventtype] || '';
if (!e.eventIcon) { if (!e.eventIcon) {
e.eventIcon = this.courseProvider.getModuleIconSrc(e.modulename); e.eventIcon = this.courseProvider.getModuleIconSrc(e.modulename);
e.moduleIcon = e.eventIcon; e.moduleIcon = e.eventIcon;
@ -309,6 +309,37 @@ export class AddonCalendarHelperProvider {
return false; return false;
} }
/**
* Filter events to be shown on the events list.
*
* @param events Events without filtering.
* @param filter Filter from popover.
* @param categories Categories indexed by ID.
* @return Filtered events.
*/
getFilteredEvents(events: any[], filter: any, categories: any): any[] {
// Do not filter.
if (!filter.filtered) {
return events;
}
const courseId = filter.courseId ? Number(filter.courseId) : undefined;
if (!courseId || courseId < 0) {
// Filter only by type.
return events.filter((event) => {
return filter[event.formattedType];
});
}
const categoryId = filter.categoryId ? Number(filter.categoryId) : undefined;
return events.filter((event) => {
return filter[event.formattedType] &&
this.shouldDisplayEvent(event, courseId, categoryId, categories);
});
}
/** /**
* Check if an event should be displayed based on the filter. * Check if an event should be displayed based on the filter.
* *
@ -352,8 +383,10 @@ export class AddonCalendarHelperProvider {
return false; return false;
} }
const eventCourse = (event.course && event.course.id) || event.courseid;
// Show the event if it is from site home or if it matches the selected course. // Show the event if it is from site home or if it matches the selected course.
return event.course && (event.course.id == this.sitesProvider.getCurrentSiteHomeId() || event.course.id == courseId); return eventCourse && (eventCourse == this.sitesProvider.getCurrentSiteHomeId() || eventCourse == courseId);
} }
/** /**

View File

@ -88,8 +88,10 @@
"addon.calendar.calendarevent": "Calendar event", "addon.calendar.calendarevent": "Calendar event",
"addon.calendar.calendarevents": "Calendar events", "addon.calendar.calendarevents": "Calendar events",
"addon.calendar.calendarreminders": "Calendar reminders", "addon.calendar.calendarreminders": "Calendar reminders",
"addon.calendar.categoryevents": "Category events",
"addon.calendar.confirmeventdelete": "Are you sure you want to delete the \"{{$a}}\" event?", "addon.calendar.confirmeventdelete": "Are you sure you want to delete the \"{{$a}}\" event?",
"addon.calendar.confirmeventseriesdelete": "The \"{{$a.name}}\" event is part of a series. Do you want to delete just this event, or all {{$a.count}} events in the series?", "addon.calendar.confirmeventseriesdelete": "The \"{{$a.name}}\" event is part of a series. Do you want to delete just this event, or all {{$a.count}} events in the series?",
"addon.calendar.courseevents": "Course events",
"addon.calendar.currentmonth": "Current Month", "addon.calendar.currentmonth": "Current Month",
"addon.calendar.daynext": "Next day", "addon.calendar.daynext": "Next day",
"addon.calendar.dayprev": "Previous day", "addon.calendar.dayprev": "Previous day",
@ -113,6 +115,7 @@
"addon.calendar.fri": "Fri", "addon.calendar.fri": "Fri",
"addon.calendar.friday": "Friday", "addon.calendar.friday": "Friday",
"addon.calendar.gotoactivity": "Go to activity", "addon.calendar.gotoactivity": "Go to activity",
"addon.calendar.groupevents": "Group events",
"addon.calendar.invalidtimedurationminutes": "The duration in minutes you have entered is invalid. Please enter the duration in minutes greater than 0 or select no duration.", "addon.calendar.invalidtimedurationminutes": "The duration in minutes you have entered is invalid. Please enter the duration in minutes greater than 0 or select no duration.",
"addon.calendar.invalidtimedurationuntil": "The date and time you selected for duration until is before the start time of the event. Please correct this before proceeding.", "addon.calendar.invalidtimedurationuntil": "The date and time you selected for duration until is before the start time of the event. Please correct this before proceeding.",
"addon.calendar.mon": "Mon", "addon.calendar.mon": "Mon",
@ -130,6 +133,7 @@
"addon.calendar.sat": "Sat", "addon.calendar.sat": "Sat",
"addon.calendar.saturday": "Saturday", "addon.calendar.saturday": "Saturday",
"addon.calendar.setnewreminder": "Set a new reminder", "addon.calendar.setnewreminder": "Set a new reminder",
"addon.calendar.siteevents": "Site events",
"addon.calendar.sun": "Sun", "addon.calendar.sun": "Sun",
"addon.calendar.sunday": "Sunday", "addon.calendar.sunday": "Sunday",
"addon.calendar.thu": "Thu", "addon.calendar.thu": "Thu",
@ -148,6 +152,7 @@
"addon.calendar.typesite": "Site event", "addon.calendar.typesite": "Site event",
"addon.calendar.typeuser": "User event", "addon.calendar.typeuser": "User event",
"addon.calendar.upcomingevents": "Upcoming events", "addon.calendar.upcomingevents": "Upcoming events",
"addon.calendar.userevents": "User events",
"addon.calendar.wed": "Wed", "addon.calendar.wed": "Wed",
"addon.calendar.wednesday": "Wednesday", "addon.calendar.wednesday": "Wednesday",
"addon.calendar.when": "When", "addon.calendar.when": "When",
@ -1517,6 +1522,7 @@
"core.fileuploader.uploading": "Uploading", "core.fileuploader.uploading": "Uploading",
"core.fileuploader.uploadingperc": "Uploading: {{$a}}%", "core.fileuploader.uploadingperc": "Uploading: {{$a}}%",
"core.fileuploader.video": "Video", "core.fileuploader.video": "Video",
"core.filter": "Filter",
"core.folder": "Folder", "core.folder": "Folder",
"core.forcepasswordchangenotice": "You must change your password to proceed.", "core.forcepasswordchangenotice": "You must change your password to proceed.",
"core.fulllistofcourses": "All courses", "core.fulllistofcourses": "All courses",

View File

@ -120,6 +120,7 @@
"invalidformdata": "Incorrect form data", "invalidformdata": "Incorrect form data",
"ios": "iOS", "ios": "iOS",
"labelsep": ":", "labelsep": ":",
"filter": "Filter",
"lastaccess": "Last access", "lastaccess": "Last access",
"lastdownloaded": "Last downloaded", "lastdownloaded": "Last downloaded",
"lastmodified": "Last modified", "lastmodified": "Last modified",