commit
d580036cbf
|
@ -21,12 +21,21 @@
|
|||
</core-empty-box>
|
||||
|
||||
<ion-list *ngIf="filteredEvents && filteredEvents.length" no-margin>
|
||||
<a ion-item text-wrap *ngFor="let event of filteredEvents" [title]="event.name" (click)="gotoEvent(event.id)" [class.core-split-item-selected]="event.id == eventId">
|
||||
<img *ngIf="event.moduleIcon" src="{{event.moduleIcon}}" item-start class="core-module-icon">
|
||||
<core-icon *ngIf="event.icon && !event.moduleIcon" [name]="event.icon" item-start></core-icon>
|
||||
<h2><core-format-text [text]="event.name"></core-format-text></h2>
|
||||
<p>{{ event.timestart | coreToLocaleString }}</p>
|
||||
</a>
|
||||
<ng-container *ngFor="let event of filteredEvents">
|
||||
<ion-item-divider *ngIf="event.showDate">
|
||||
{{ event.timestart * 1000 | coreFormatDate: "strftimedayshort" }}
|
||||
</ion-item-divider>
|
||||
<a ion-item text-wrap [title]="event.name" (click)="gotoEvent(event.id)" [class.core-split-item-selected]="event.id == eventId">
|
||||
<img *ngIf="event.moduleIcon" src="{{event.moduleIcon}}" item-start class="core-module-icon">
|
||||
<core-icon *ngIf="event.icon && !event.moduleIcon" [name]="event.icon" item-start></core-icon>
|
||||
<h2><core-format-text [text]="event.name"></core-format-text></h2>
|
||||
<p>
|
||||
{{ event.timestart * 1000 | coreFormatDate: "strftimetime" }}
|
||||
<span *ngIf="event.timeduration && event.endsSameDay"> - {{ (event.timestart + event.timeduration) * 1000 | coreFormatDate: "strftimetime" }}</span>
|
||||
<span *ngIf="event.timeduration && !event.endsSameDay"> - {{ (event.timestart + event.timeduration) | coreToLocaleString }}</span>
|
||||
</p>
|
||||
</a>
|
||||
</ng-container>
|
||||
</ion-list>
|
||||
|
||||
<core-infinite-loading [enabled]="canLoadMore" (action)="loadMoreEvents($event)" [error]="loadMoreError"></core-infinite-loading>
|
||||
|
|
|
@ -26,6 +26,7 @@ import { CoreCoursePickerMenuPopoverComponent } from '@components/course-picker-
|
|||
import { CoreEventsProvider } from '@providers/events';
|
||||
import { CoreAppProvider } from '@providers/app';
|
||||
import { CoreSplitViewComponent } from '@components/split-view/split-view';
|
||||
import * as moment from 'moment';
|
||||
|
||||
/**
|
||||
* Page that displays the list of calendar events.
|
||||
|
@ -147,6 +148,10 @@ export class AddonCalendarListPage implements OnDestroy {
|
|||
} else {
|
||||
// Sort the events by timestart, they're ordered by id.
|
||||
events.sort((a, b) => {
|
||||
if (a.timestart == b.timestart) {
|
||||
return a.timeduration - b.timeduration;
|
||||
}
|
||||
|
||||
return a.timestart - b.timestart;
|
||||
});
|
||||
|
||||
|
@ -160,6 +165,12 @@ export class AddonCalendarListPage implements OnDestroy {
|
|||
this.events = this.utils.mergeArraysWithoutDuplicates(this.events, events, 'id');
|
||||
}
|
||||
this.filteredEvents = this.getFilteredEvents();
|
||||
|
||||
// Calculate which evemts need to display the date.
|
||||
this.filteredEvents.forEach((event, index): any => {
|
||||
event.showDate = this.showDate(event, this.filteredEvents[index - 1]);
|
||||
event.endsSameDay = this.endsSameDay(event);
|
||||
});
|
||||
this.canLoadMore = true;
|
||||
|
||||
// Schedule notifications for the events retrieved (might have new events).
|
||||
|
@ -308,6 +319,40 @@ export class AddonCalendarListPage implements OnDestroy {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Check date should be shown on event list for the current event.
|
||||
* If date has changed from previous to current event it should be shown.
|
||||
*
|
||||
* @param {any} event Current event where to show the date.
|
||||
* @param {any} [prevEvent] Previous event where to compare the date with.
|
||||
* @return {boolean} If date has changed and should be shown.
|
||||
*/
|
||||
protected showDate(event: any, prevEvent?: any): boolean {
|
||||
if (!prevEvent) {
|
||||
// First event, show it.
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if day has changed.
|
||||
return !moment(event.timestart * 1000).isSame(prevEvent.timestart * 1000, 'day');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if event ends the same date or not.
|
||||
*
|
||||
* @param {any} event Event info.
|
||||
* @return {boolean} If date has changed and should be shown.
|
||||
*/
|
||||
protected endsSameDay(event: any): boolean {
|
||||
if (!event.timeduration) {
|
||||
// No duration.
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if day has changed.
|
||||
return moment(event.timestart * 1000).isSame((event.timestart + event.timeduration) * 1000, 'day');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the context menu.
|
||||
*
|
||||
|
|
|
@ -138,6 +138,37 @@ export class AddonCalendarProvider {
|
|||
this.sitesProvider.createTablesFromSchema(this.tablesSchema);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes expired events from local DB.
|
||||
*
|
||||
* @param {string} [siteId] ID of the site the event belongs to. If not defined, use current site.
|
||||
* @return {Promise<void>} Promise resolved when done.
|
||||
*/
|
||||
cleanExpiredEvents(siteId?: string): Promise<void> {
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
let promise;
|
||||
|
||||
// Cancel expired events notifications first.
|
||||
if (this.localNotificationsProvider.isAvailable()) {
|
||||
promise = site.getDb().getRecordsSelect(AddonCalendarProvider.EVENTS_TABLE, 'timestart < ?',
|
||||
[this.timeUtils.timestamp()]).then((events) => {
|
||||
events.forEach((event) => {
|
||||
return this.localNotificationsProvider.cancel(event.id, AddonCalendarProvider.COMPONENT, site.getId());
|
||||
});
|
||||
}).catch(() => {
|
||||
// Ignore errors.
|
||||
});
|
||||
} else {
|
||||
promise = Promise.resolve();
|
||||
}
|
||||
|
||||
return promise.then(() => {
|
||||
return site.getDb().deleteRecordsSelect(AddonCalendarProvider.EVENTS_TABLE, 'timestart < ?',
|
||||
[this.timeUtils.timestamp()]);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all calendar events from local Db.
|
||||
*
|
||||
|
@ -442,27 +473,29 @@ export class AddonCalendarProvider {
|
|||
* @return {Promise} Promise resolved when all the notifications have been scheduled.
|
||||
*/
|
||||
scheduleAllSitesEventsNotifications(): Promise<any[]> {
|
||||
if (this.localNotificationsProvider.isAvailable()) {
|
||||
return this.sitesProvider.getSitesIds().then((siteIds) => {
|
||||
const promises = [];
|
||||
const notificationsEnabled = this.localNotificationsProvider.isAvailable();
|
||||
|
||||
siteIds.forEach((siteId) => {
|
||||
// Check if calendar is disabled for the site.
|
||||
promises.push(this.isDisabled(siteId).then((disabled) => {
|
||||
if (!disabled) {
|
||||
// Get first events.
|
||||
return this.getEventsList(undefined, undefined, siteId).then((events) => {
|
||||
return this.scheduleEventsNotifications(events, siteId);
|
||||
});
|
||||
}
|
||||
}));
|
||||
});
|
||||
return this.sitesProvider.getSitesIds().then((siteIds) => {
|
||||
const promises = [];
|
||||
|
||||
return Promise.all(promises);
|
||||
siteIds.forEach((siteId) => {
|
||||
promises.push(this.cleanExpiredEvents(siteId).then(() => {
|
||||
if (notificationsEnabled) {
|
||||
// Check if calendar is disabled for the site.
|
||||
return this.isDisabled(siteId).then((disabled) => {
|
||||
if (!disabled) {
|
||||
// Get first events.
|
||||
return this.getEventsList(undefined, undefined, siteId).then((events) => {
|
||||
return this.scheduleEventsNotifications(events, siteId);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}));
|
||||
});
|
||||
} else {
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
|
||||
return Promise.all(promises);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -21,6 +21,11 @@ ion-app.app-root.md {
|
|||
@include margin-horizontal($item-md-padding-start + ($item-md-padding-start / 2) - 1, null);
|
||||
}
|
||||
|
||||
.item-md img[item-start] + .item-inner,
|
||||
.item-md img[item-start] + .item-input {
|
||||
@include margin-horizontal($item-md-padding-start + ($item-md-padding-start / 2), null);
|
||||
}
|
||||
|
||||
@each $color-name, $color-base, $color-contrast in get-colors($colors-md) {
|
||||
.core-#{$color-name}-card {
|
||||
@extend .card-md;
|
||||
|
|
|
@ -943,6 +943,12 @@ details summary {
|
|||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.icon.fa-graduation-cap{
|
||||
font-size: 21px;
|
||||
width: 21px;
|
||||
line-height: 28px;
|
||||
}
|
||||
|
||||
// Fix iframes in fullscreen mode.
|
||||
//
|
||||
// Ionic sets "contain: strict" to some elements. This enables paint containment,
|
||||
|
|
|
@ -17,7 +17,9 @@ ion-app.app-root.wp {
|
|||
}
|
||||
|
||||
.item-wp ion-spinner[item-start] + .item-inner,
|
||||
.item-wp ion-spinner[item-start] + .item-input {
|
||||
.item-wp ion-spinner[item-start] + .item-input,
|
||||
.item-wp img[item-start] + .item-inner,
|
||||
.item-wp img[item-start] + .item-input {
|
||||
@include margin-horizontal(($item-wp-padding-start / 2), null);
|
||||
}
|
||||
|
||||
|
|
|
@ -23,8 +23,11 @@
|
|||
|
||||
<!-- Course summary. By default we only display the course progress. -->
|
||||
<core-dynamic-component [component]="courseSummaryComponent" [data]="data">
|
||||
<ion-list no-lines *ngIf="selectedSection && selectedSection.id == allSectionsId && course.progress != null && course.progress >= 0" class="core-format-progress-list">
|
||||
<ion-item class="core-course-progress">
|
||||
<ion-list no-lines *ngIf="course.imageThumb || (selectedSection && selectedSection.id == allSectionsId && course.progress != null && course.progress >= 0)" class="core-format-progress-list">
|
||||
<div *ngIf="course.imageThumb" class="core-course-thumb">
|
||||
<img [src]="course.imageThumb" core-external-content alt=""/>
|
||||
</div>
|
||||
<ion-item class="core-course-progress" *ngIf="selectedSection && selectedSection.id == allSectionsId && course.progress != null && course.progress >= 0">
|
||||
<core-progress-bar [progress]="course.progress"></core-progress-bar>
|
||||
</ion-item>
|
||||
</ion-list>
|
||||
|
|
|
@ -34,6 +34,7 @@ ion-app.app-root core-course-format {
|
|||
}
|
||||
|
||||
.core-course-thumb {
|
||||
display: none;
|
||||
height: 150px;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
|
|
|
@ -138,4 +138,8 @@ ion-app.app-root.wp core-course-module {
|
|||
margin-top: 8px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
ion-app.app-root a.core-course-module-handler.item [item-start] + .item-inner {
|
||||
@include margin-horizontal(4px, null);
|
||||
}
|
|
@ -265,6 +265,11 @@ export class CoreCourseSectionPage implements OnDestroy {
|
|||
});
|
||||
}));
|
||||
|
||||
// Get the overview files.
|
||||
if (this.course.overviewfiles) {
|
||||
this.course.imageThumb = this.course.overviewfiles[0] && this.course.overviewfiles[0].fileurl;
|
||||
}
|
||||
|
||||
// Load the course handlers.
|
||||
promises.push(this.courseOptionsDelegate.getHandlersToDisplay(this.injector, this.course, refresh, false)
|
||||
.then((handlers) => {
|
||||
|
|
|
@ -97,14 +97,13 @@ export class CoreSitePluginsHelperProvider {
|
|||
this.logger = logger.getInstance('CoreSitePluginsHelperProvider');
|
||||
|
||||
// Fetch the plugins on login.
|
||||
eventsProvider.on(CoreEventsProvider.LOGIN, () => {
|
||||
const siteId = this.sitesProvider.getCurrentSiteId();
|
||||
this.fetchSitePlugins(siteId).then((plugins) => {
|
||||
eventsProvider.on(CoreEventsProvider.LOGIN, (data) => {
|
||||
this.fetchSitePlugins(data.siteId).then((plugins) => {
|
||||
// Plugins fetched, check that site hasn't changed.
|
||||
if (siteId == this.sitesProvider.getCurrentSiteId() && plugins.length) {
|
||||
if (data.siteId == this.sitesProvider.getCurrentSiteId() && plugins.length) {
|
||||
// Site is still the same. Load the plugins and trigger the event.
|
||||
this.loadSitePlugins(plugins).then(() => {
|
||||
eventsProvider.trigger(CoreEventsProvider.SITE_PLUGINS_LOADED, {}, siteId);
|
||||
eventsProvider.trigger(CoreEventsProvider.SITE_PLUGINS_LOADED, {}, data.siteId);
|
||||
});
|
||||
|
||||
}
|
||||
|
|
|
@ -489,7 +489,9 @@ export class CoreLocalNotificationsProvider {
|
|||
|
||||
// Remove from triggered, since the notification could be in there with a different time.
|
||||
this.removeTriggered(notification.id);
|
||||
this.localNotifications.schedule(notification);
|
||||
this.localNotifications.cancel(notification.id).finally(() => {
|
||||
this.localNotifications.schedule(notification);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1062,7 +1062,9 @@ export class CoreSitesProvider {
|
|||
updateSiteToken(siteUrl: string, username: string, token: string, privateToken: string = ''): Promise<any> {
|
||||
const siteId = this.createSiteID(siteUrl, username);
|
||||
|
||||
return this.updateSiteTokenBySiteId(siteId, token, privateToken);
|
||||
return this.updateSiteTokenBySiteId(siteId, token, privateToken).then(() => {
|
||||
return this.login(siteId);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue