From b24cbab4004d8c070327236371951f47371ffd7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pau=20Ferrer=20Oca=C3=B1a?= Date: Thu, 22 Aug 2019 12:49:38 +0200 Subject: [PATCH 1/6] MOBILE-3021 calendar: UX improvements --- scripts/langindex.json | 1 + .../calendar/addon-calendar-calendar.html | 17 +++---- .../components/calendar/calendar.scss | 44 ++++++++++++++----- .../calendar/components/calendar/calendar.ts | 38 +++++++++++++++- src/addon/calendar/lang/en.json | 1 + src/addon/calendar/pages/day/day.html | 11 +++-- src/addon/calendar/pages/day/day.ts | 20 ++++++++- src/addon/calendar/pages/index/index.html | 11 ++--- src/addon/calendar/pages/index/index.scss | 3 -- src/addon/calendar/pages/list/list.html | 3 +- src/assets/lang/en.json | 1 + 11 files changed, 109 insertions(+), 41 deletions(-) delete mode 100644 src/addon/calendar/pages/index/index.scss diff --git a/scripts/langindex.json b/scripts/langindex.json index 8819689b2..fe54142bd 100644 --- a/scripts/langindex.json +++ b/scripts/langindex.json @@ -91,6 +91,7 @@ "addon.calendar.calendarreminders": "local_moodlemobileapp", "addon.calendar.confirmeventdelete": "calendar", "addon.calendar.confirmeventseriesdelete": "calendar", + "addon.calendar.currentmonth": "local_moodlemobileapp", "addon.calendar.daynext": "calendar", "addon.calendar.dayprev": "calendar", "addon.calendar.defaultnotificationtime": "local_moodlemobileapp", diff --git a/src/addon/calendar/components/calendar/addon-calendar-calendar.html b/src/addon/calendar/components/calendar/addon-calendar-calendar.html index bf5c29422..030377251 100644 --- a/src/addon/calendar/components/calendar/addon-calendar-calendar.html +++ b/src/addon/calendar/components/calendar/addon-calendar-calendar.html @@ -1,9 +1,9 @@ - + + + @@ -31,15 +31,16 @@ - {{ day.shortname | translate }} + {{ day.shortname | translate }} + {{ day.fullname | translate }} - -

{{ day.mday }}

+ +

{{ day.mday }}

@@ -47,12 +48,12 @@
-

+

- {{ event.timestart * 1000 | coreFormatDate: timeFormat }} + {{event.name}}

diff --git a/src/addon/calendar/components/calendar/calendar.scss b/src/addon/calendar/components/calendar/calendar.scss index 278e56bcf..ff2d77c97 100644 --- a/src/addon/calendar/components/calendar/calendar.scss +++ b/src/addon/calendar/components/calendar/calendar.scss @@ -32,17 +32,34 @@ ion-app.app-root addon-calendar-calendar { @include border-end(0, null, null); @include padding(null, 8px, null, null); } - .addon-calendar-day-number { - height: 24px; - line-height: 24px; - width: max-content; - min-width: 24px; - text-align: center; - font-weight: 500; - display: inline-block; - margin: 3px; + + &.addon-calendar-event-past-day > .addon-calendar-dot-types, + &.addon-calendar-event-past-day > .addon-calendar-day-events { + opacity: 0.5; } - &.today .addon-calendar-day-number { + + .addon-calendar-day-number { + margin: 0; + + span { + line-height: 24px; + font-weight: 500; + display: inline-block; + margin: 3px; + width: max-content; + width: 24px; + height: 24px; + text-align: center; + } + } + + @include media-breakpoint-up(md) { + .addon-calendar-day-number { + text-align: left; + } + } + + &.today .addon-calendar-day-number span { background-color: $calendar-today-bgcolor; color: $calendar-today-color; @@ -58,6 +75,10 @@ ion-app.app-root addon-calendar-calendar { overflow: hidden; white-space: nowrap; + &.addon-calendar-event-past { + opacity: 0.5; + } + .addon-calendar-event-name { font-weight: 500; } @@ -81,7 +102,6 @@ ion-app.app-root addon-calendar-calendar { } .addon-calendar-weekday { - color: $gray-dark; border-bottom: 1px solid $list-md-border-color; } @@ -130,6 +150,6 @@ ion-app.app-root addon-calendar-calendar { width: 16px; height: 16px; display: inline-block; - vertical-align: middle; + vertical-align: bottom; } } \ No newline at end of file diff --git a/src/addon/calendar/components/calendar/calendar.ts b/src/addon/calendar/components/calendar/calendar.ts index a620fe6ee..985f284c8 100644 --- a/src/addon/calendar/components/calendar/calendar.ts +++ b/src/addon/calendar/components/calendar/calendar.ts @@ -48,6 +48,7 @@ export class AddonCalendarCalendarComponent implements OnInit, OnChanges, OnDest loaded = false; timeFormat: string; isCurrentMonth: boolean; + isPastMonth: boolean; protected year: number; protected month: number; @@ -57,6 +58,7 @@ export class AddonCalendarCalendarComponent implements OnInit, OnChanges, OnDest protected offlineEvents: {[monthId: string]: {[day: number]: any[]}} = {}; // Offline events classified in month & day. protected offlineEditedEventsIds = []; // IDs of events edited in offline. protected deletedEvents = []; // Events deleted in offline. + protected currentTime: number; // Observers. protected undeleteEventObserver: any; @@ -200,6 +202,28 @@ export class AddonCalendarCalendarComponent implements OnInit, OnChanges, OnDest this.weekDays = this.calendarProvider.getWeekDays(result.daynames[0].dayno); this.weeks = result.weeks; + this.calculateIsCurrentMonth(); + + if (this.isCurrentMonth) { + let isPast = true; + this.weeks.forEach((week) => { + week.days.some((day) => { + day.ispast = isPast && !day.istoday; + isPast = day.ispast; + + if (day.istoday) { + day.events.forEach((event) => { + event.ispast = this.isEventPast(event); + }); + + return true; + } + + return day.istoday; + }); + }); + } + // Merge the online events with offline data. this.mergeEvents(); @@ -288,7 +312,6 @@ export class AddonCalendarCalendarComponent implements OnInit, OnChanges, OnDest this.domUtils.showErrorModalDefault(error, 'addon.calendar.errorloadevents', true); this.decreaseMonth(); }).finally(() => { - this.calculateIsCurrentMonth(); this.loaded = true; }); } @@ -305,7 +328,6 @@ export class AddonCalendarCalendarComponent implements OnInit, OnChanges, OnDest this.domUtils.showErrorModalDefault(error, 'addon.calendar.errorloadevents', true); this.increaseMonth(); }).finally(() => { - this.calculateIsCurrentMonth(); this.loaded = true; }); } @@ -336,7 +358,10 @@ export class AddonCalendarCalendarComponent implements OnInit, OnChanges, OnDest calculateIsCurrentMonth(): void { const now = new Date(); + this.currentTime = this.timeUtils.timestamp(); + this.isCurrentMonth = this.year == now.getFullYear() && this.month == now.getMonth() + 1; + this.isPastMonth = this.year < now.getFullYear() || (this.year == now.getFullYear() && this.month < now.getMonth() + 1); } /** @@ -466,6 +491,15 @@ export class AddonCalendarCalendarComponent implements OnInit, OnChanges, OnDest }); } + /** + * Returns if the event is in the past or not. + * @param {any} event Event object. + * @return {boolean} True if it's in the past. + */ + isEventPast(event: any): boolean { + return (event.timestart + event.timeduration) < this.currentTime; + } + /** * Component destroyed. */ diff --git a/src/addon/calendar/lang/en.json b/src/addon/calendar/lang/en.json index be2bab15a..ea79d56e5 100644 --- a/src/addon/calendar/lang/en.json +++ b/src/addon/calendar/lang/en.json @@ -6,6 +6,7 @@ "calendarreminders": "Calendar reminders", "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?", + "currentmonth": "Current Month", "daynext": "Next day", "dayprev": "Previous day", "defaultnotificationtime": "Default notification time", diff --git a/src/addon/calendar/pages/day/day.html b/src/addon/calendar/pages/day/day.html index cec0955ac..9cfd3705a 100644 --- a/src/addon/calendar/pages/day/day.html +++ b/src/addon/calendar/pages/day/day.html @@ -2,13 +2,12 @@ {{ 'addon.calendar.calendarevents' | translate }} - + @@ -49,7 +48,7 @@ - +

@@ -62,7 +61,7 @@ {{ 'core.deletedoffline' | translate }} -
+
diff --git a/src/addon/calendar/pages/day/day.ts b/src/addon/calendar/pages/day/day.ts index 73202cfd3..cc930e728 100644 --- a/src/addon/calendar/pages/day/day.ts +++ b/src/addon/calendar/pages/day/day.ts @@ -51,6 +51,7 @@ export class AddonCalendarDayPage implements OnInit, OnDestroy { protected deletedEvents = []; // Events deleted in offline. protected timeFormat: string; protected currentMoment: moment.Moment; + protected currentTime: number; // Observers. protected newEventObserver: any; @@ -74,6 +75,7 @@ export class AddonCalendarDayPage implements OnInit, OnDestroy { isOnline = false; syncIcon: string; isCurrentDay: boolean; + isPastDay: boolean; constructor(localNotificationsProvider: CoreLocalNotificationsProvider, navParams: NavParams, @@ -308,9 +310,12 @@ export class AddonCalendarDayPage implements OnInit, OnDestroy { // Filter events by course. this.filterEvents(); + this.calculateIsCurrentDay(); + // Re-calculate the formatted time so it uses the device date. const dayTime = this.currentMoment.unix() * 1000; this.events.forEach((event) => { + event.ispast = this.isPastDay || (this.isCurrentDay && this.isEventPast(event)); promises.push(this.calendarProvider.formatEventTime(event, this.timeFormat, true, dayTime).then((time) => { event.formattedtime = time; })); @@ -555,7 +560,11 @@ export class AddonCalendarDayPage implements OnInit, OnDestroy { calculateIsCurrentDay(): void { const now = new Date(); + this.currentTime = this.timeUtils.timestamp(); + this.isCurrentDay = this.year == now.getFullYear() && this.month == now.getMonth() + 1 && this.day == now.getDate(); + this.isPastDay = this.year < now.getFullYear() || (this.year == now.getFullYear() && this.month < now.getMonth()) || + (this.year == now.getFullYear() && this.month == now.getMonth() + 1 && this.day < now.getDate()); } /** @@ -600,7 +609,6 @@ export class AddonCalendarDayPage implements OnInit, OnDestroy { this.domUtils.showErrorModalDefault(error, 'addon.calendar.errorloadevents', true); this.decreaseDay(); }).finally(() => { - this.calculateIsCurrentDay(); this.loaded = true; }); } @@ -617,7 +625,6 @@ export class AddonCalendarDayPage implements OnInit, OnDestroy { this.domUtils.showErrorModalDefault(error, 'addon.calendar.errorloadevents', true); this.increaseDay(); }).finally(() => { - this.calculateIsCurrentDay(); this.loaded = true; }); } @@ -665,6 +672,15 @@ export class AddonCalendarDayPage implements OnInit, OnDestroy { return false; } + /** + * Returns if the event is in the past or not. + * @param {any} event Event object. + * @return {boolean} True if it's in the past. + */ + isEventPast(event: any): boolean { + return (event.timestart + event.timeduration) < this.currentTime; + } + /** * Page destroyed. */ diff --git a/src/addon/calendar/pages/index/index.html b/src/addon/calendar/pages/index/index.html index fc6386e36..d2d6d38b0 100644 --- a/src/addon/calendar/pages/index/index.html +++ b/src/addon/calendar/pages/index/index.html @@ -2,16 +2,13 @@ {{ (showCalendar ? 'addon.calendar.calendarevents' : 'addon.calendar.upcomingevents') | translate }} - - + + diff --git a/src/addon/calendar/pages/index/index.scss b/src/addon/calendar/pages/index/index.scss deleted file mode 100644 index 213b8abe5..000000000 --- a/src/addon/calendar/pages/index/index.scss +++ /dev/null @@ -1,3 +0,0 @@ -page-addon-calendar-index .toolbar-ios ion-title { - @include padding-horizontal(null, 120px); -} \ No newline at end of file diff --git a/src/addon/calendar/pages/list/list.html b/src/addon/calendar/pages/list/list.html index bd5c848ad..2d85b3f1d 100644 --- a/src/addon/calendar/pages/list/list.html +++ b/src/addon/calendar/pages/list/list.html @@ -3,7 +3,8 @@ {{ 'addon.calendar.calendarevents' | translate }} diff --git a/src/assets/lang/en.json b/src/assets/lang/en.json index 8c35aeb95..831223df1 100644 --- a/src/assets/lang/en.json +++ b/src/assets/lang/en.json @@ -90,6 +90,7 @@ "addon.calendar.calendarreminders": "Calendar reminders", "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.currentmonth": "Current Month", "addon.calendar.daynext": "Next day", "addon.calendar.dayprev": "Previous day", "addon.calendar.defaultnotificationtime": "Default notification time", From cb9b936b3ccb25d96926b488ea43992f6a44a31c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pau=20Ferrer=20Oca=C3=B1a?= Date: Thu, 22 Aug 2019 15:38:13 +0200 Subject: [PATCH 2/6] MOBILE-3068 styles: Fix RTE image sizing --- src/theme/format-text.scss | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/src/theme/format-text.scss b/src/theme/format-text.scss index a14ee433e..8365e7363 100644 --- a/src/theme/format-text.scss +++ b/src/theme/format-text.scss @@ -96,8 +96,6 @@ ion-app.app-root core-rich-text-editor .core-rte-editor { .atto_image_button_right { vertical-align: middle; max-width: 100%; - height: auto; - width: auto; display: inline-block; margin: 0 0.5em; @@ -105,8 +103,6 @@ ion-app.app-root core-rich-text-editor .core-rte-editor { /* If the image is display: block then linking the image to URLs won't work. */ /*display: inline-block;*/ max-width: 100%; - height: auto; - width: auto; } } @@ -179,6 +175,24 @@ ion-app.app-root core-rich-text-editor .core-rte-editor { } } +// Those styles are omitted on RTE. +ion-app.app-root core-format-text, +ion-app.app-root .item core-format-text { + .atto_image_button_text-top, + .atto_image_button_middle, + .atto_image_button_text-bottom, + .atto_image_button_left, + .atto_image_button_right { + height: auto; + width: auto; + + &.img-responsive { + height: auto; + width: auto; + } + } +} + // Special fixes // ------------------------- ion-app.app-root { From 51403efcca33f4827511e5d3da5f84eb3d2b2eb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pau=20Ferrer=20Oca=C3=B1a?= Date: Thu, 22 Aug 2019 17:15:33 +0200 Subject: [PATCH 3/6] MOBILE-3068 core: Fix some uncaught promises --- src/core/course/course.module.ts | 4 +++- src/core/siteplugins/providers/helper.ts | 2 ++ src/providers/sites.ts | 2 ++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/core/course/course.module.ts b/src/core/course/course.module.ts index d14844582..52a686a40 100644 --- a/src/core/course/course.module.ts +++ b/src/core/course/course.module.ts @@ -96,7 +96,9 @@ export class CoreCourseModule { eventsProvider.on(CoreEventsProvider.LOGIN, () => { // Log the app is open to keep user in online status. setTimeout(() => { - cronDelegate.forceCronHandlerExecution(logHandler.name); + cronDelegate.forceCronHandlerExecution(logHandler.name).catch((e) => { + // Ignore errors here, since probably login is not complete: it happens on token invalid. + }); }, 1000); }); } diff --git a/src/core/siteplugins/providers/helper.ts b/src/core/siteplugins/providers/helper.ts index f046cdbb4..b6c33d0fc 100644 --- a/src/core/siteplugins/providers/helper.ts +++ b/src/core/siteplugins/providers/helper.ts @@ -114,6 +114,8 @@ export class CoreSitePluginsHelperProvider { eventsProvider.trigger(CoreEventsProvider.SITE_PLUGINS_LOADED, {}, data.siteId); }); } + }).catch((e) => { + // Ignore errors here. }).finally(() => { this.sitePluginsProvider.setPluginsFetched(); }); diff --git a/src/providers/sites.ts b/src/providers/sites.ts index 5bcb8e938..515d7117a 100644 --- a/src/providers/sites.ts +++ b/src/providers/sites.ts @@ -1385,6 +1385,8 @@ export class CoreSitesProvider { this.eventsProvider.trigger(CoreEventsProvider.SITE_UPDATED, info, siteId); }); }); + }).catch((error) => { + // Ignore that we cannot fetch site info. Probably the auth token is invalid. }); }); } From 6269849dff031eb1038c2ab09c045a32747c2da3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pau=20Ferrer=20Oca=C3=B1a?= Date: Fri, 23 Aug 2019 09:07:36 +0200 Subject: [PATCH 4/6] MOBILE-3025 blocks: Rollback scroll follow implementation --- .../core-block-course-blocks.html | 18 ++-- .../course-blocks/course-blocks.scss | 30 ------- .../components/course-blocks/course-blocks.ts | 89 +------------------ 3 files changed, 11 insertions(+), 126 deletions(-) diff --git a/src/core/block/components/course-blocks/core-block-course-blocks.html b/src/core/block/components/course-blocks/core-block-course-blocks.html index ee6af5a26..a34ada03c 100644 --- a/src/core/block/components/course-blocks/core-block-course-blocks.html +++ b/src/core/block/components/course-blocks/core-block-course-blocks.html @@ -3,14 +3,12 @@
-
- - - - - - - - -
+ + + + + + + +
diff --git a/src/core/block/components/course-blocks/course-blocks.scss b/src/core/block/components/course-blocks/course-blocks.scss index cc2c9f3c0..61fcad7be 100644 --- a/src/core/block/components/course-blocks/course-blocks.scss +++ b/src/core/block/components/course-blocks/course-blocks.scss @@ -13,10 +13,6 @@ ion-app.app-root core-block-course-blocks { &.core-has-blocks { @include media-breakpoint-up(md) { - @include position(0, 0, 0, 0); - - position: absolute; - display: flex; flex-direction: row; @@ -29,46 +25,20 @@ ion-app.app-root core-block-course-blocks { } div.core-course-blocks-side { - position: relative; - @include position(auto, 0, auto, auto); max-width: $core-side-blocks-max-width; min-width: $core-side-blocks-min-width; @include border-start(1px, solid, $list-md-border-color); - - .core-course-blocks-side-scroll { - position: absolute; - top: 0; - max-width: 100%; - min-width: 100%; - - &.core-course-blocks-fixed-bottom { - position: fixed; - bottom: 0; - top: auto; - transform: none !important; - } - - core-block { - max-width: $core-side-blocks-max-width; - min-width: $core-side-blocks-min-width; - } - } } } @include media-breakpoint-down(sm) { // Disable scroll on individual columns. div.core-course-blocks-side { - transform: none !important; height: auto; &.core-hide-blocks { display: none; } - - .core-course-blocks-side-scroll { - transform: none !important; - } } } } diff --git a/src/core/block/components/course-blocks/course-blocks.ts b/src/core/block/components/course-blocks/course-blocks.ts index 7db1ffa8c..c1b849c56 100644 --- a/src/core/block/components/course-blocks/course-blocks.ts +++ b/src/core/block/components/course-blocks/course-blocks.ts @@ -12,10 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { Component, ViewChildren, Input, OnInit, QueryList, ElementRef, OnDestroy } from '@angular/core'; +import { Component, ViewChildren, Input, OnInit, QueryList, ElementRef } from '@angular/core'; import { Content } from 'ionic-angular'; import { CoreDomUtilsProvider } from '@providers/utils/dom'; -import { CoreAppProvider } from '@providers/app'; import { CoreCourseProvider } from '@core/course/providers/course'; import { CoreBlockComponent } from '../block/block'; import { CoreBlockHelperProvider } from '../../providers/helper'; @@ -27,7 +26,7 @@ import { CoreBlockHelperProvider } from '../../providers/helper'; selector: 'core-block-course-blocks', templateUrl: 'core-block-course-blocks.html', }) -export class CoreBlockCourseBlocksComponent implements OnInit, OnDestroy { +export class CoreBlockCourseBlocksComponent implements OnInit { @Input() courseId: number; @Input() hideBlocks = false; @@ -39,16 +38,10 @@ export class CoreBlockCourseBlocksComponent implements OnInit, OnDestroy { blocks = []; protected element: HTMLElement; - protected lastScroll; - protected translationY = 0; - protected blocksScrollHeight = 0; - protected sideScroll: HTMLElement; - protected vpHeight = 0; // Viewport height. - protected scrollWorking = false; constructor(private domUtils: CoreDomUtilsProvider, private courseProvider: CoreCourseProvider, protected blockHelper: CoreBlockHelperProvider, element: ElementRef, - protected content: Content, protected appProvider: CoreAppProvider) { + protected content: Content) { this.element = element.nativeElement; } @@ -58,83 +51,9 @@ export class CoreBlockCourseBlocksComponent implements OnInit, OnDestroy { ngOnInit(): void { this.loadContent().finally(() => { this.dataLoaded = true; - - window.addEventListener('resize', this.initScroll.bind(this)); }); } - /** - * Setup scrolling. - */ - protected initScroll(): void { - if (this.blocks.length <= 0) { - return; - } - - const scroll: HTMLElement = this.content && this.content.getScrollElement(); - - this.domUtils.waitElementToExist(() => scroll && scroll.querySelector('.core-course-blocks-side')).then((sideElement) => { - const contentHeight = parseInt(this.content.getNativeElement().querySelector('.scroll-content').scrollHeight, 10); - - this.sideScroll = scroll.querySelector('.core-course-blocks-side-scroll'); - this.blocksScrollHeight = this.sideScroll.scrollHeight; - this.vpHeight = sideElement.clientHeight; - - // Check if needed and event was not init before. - if (this.appProvider.isWide() && this.vpHeight && contentHeight > this.vpHeight && - this.blocksScrollHeight > this.vpHeight) { - if (typeof this.lastScroll == 'undefined') { - this.lastScroll = 0; - scroll.addEventListener('scroll', this.scrollFunction.bind(this)); - } - this.scrollWorking = true; - } else { - this.sideScroll.style.transform = 'translate(0, 0)'; - this.sideScroll.classList.remove('core-course-blocks-fixed-bottom'); - this.scrollWorking = false; - } - }).catch(() => { - // Ignore errors. - }); - } - - /** - * Scroll function that moves the sidebar if needed. - * - * @param {Event} e Event to get the target from. - */ - protected scrollFunction(e: Event): void { - if (!this.scrollWorking) { - return; - } - - const target: any = e.target, - top = parseInt(target.scrollTop, 10), - goingUp = top < this.lastScroll; - if (goingUp) { - this.sideScroll.classList.remove('core-course-blocks-fixed-bottom'); - if (top <= this.translationY ) { - // Fixed to top. - this.translationY = top; - this.sideScroll.style.transform = 'translate(0, ' + this.translationY + 'px)'; - } - } else if (top - this.translationY >= (this.blocksScrollHeight - this.vpHeight)) { - // Fixed to bottom. - this.sideScroll.classList.add('core-course-blocks-fixed-bottom'); - this.translationY = top - (this.blocksScrollHeight - this.vpHeight); - this.sideScroll.style.transform = 'translate(0, ' + this.translationY + 'px)'; - } - - this.lastScroll = top; - } - - /** - * Component destroyed. - */ - ngOnDestroy(): void { - window.removeEventListener('resize', this.initScroll); - } - /** * Invalidate blocks data. * @@ -175,8 +94,6 @@ export class CoreBlockCourseBlocksComponent implements OnInit, OnDestroy { this.element.classList.remove('core-no-blocks'); this.content.getElementRef().nativeElement.classList.add('core-course-block-with-blocks'); - - this.initScroll(); } else { this.element.classList.remove('core-has-blocks'); this.element.classList.add('core-no-blocks'); From f3a51a3717f148e70a53c43024f3ca59bbb08467 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pau=20Ferrer=20Oca=C3=B1a?= Date: Fri, 23 Aug 2019 10:14:28 +0200 Subject: [PATCH 5/6] MOBILE-3068 tabs: Fix scroll problem on calculating tabs --- src/components/tabs/tabs.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/components/tabs/tabs.ts b/src/components/tabs/tabs.ts index 921143228..bf1b3c6cd 100644 --- a/src/components/tabs/tabs.ts +++ b/src/components/tabs/tabs.ts @@ -234,7 +234,15 @@ export class CoreTabsComponent implements OnInit, AfterViewInit, OnChanges, OnDe */ calculateTabBarHeight(): void { this.tabBarHeight = this.topTabsElement.offsetHeight; - this.originalTabsContainer.style.paddingBottom = this.tabBarHeight + 'px'; + + if (this.tabsShown) { + // Smooth translation. + this.topTabsElement.style.transform = 'translateY(-' + this.lastScroll + 'px)'; + this.originalTabsContainer.style.transform = 'translateY(-' + this.lastScroll + 'px)'; + this.originalTabsContainer.style.paddingBottom = this.tabBarHeight - this.lastScroll + 'px'; + } else { + this.tabBarElement.classList.add('tabs-hidden'); + } } /** From fd6c700ff8587604641473426596f40ab3382622 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pau=20Ferrer=20Oca=C3=B1a?= Date: Fri, 23 Aug 2019 13:33:53 +0200 Subject: [PATCH 6/6] MOBILE-3068 blogs: Fix infinite loading performance on my entries --- .../entries/addon-blog-entries.html | 4 +- src/addon/blog/components/entries/entries.ts | 71 ++++++++++++++++--- 2 files changed, 63 insertions(+), 12 deletions(-) diff --git a/src/addon/blog/components/entries/addon-blog-entries.html b/src/addon/blog/components/entries/addon-blog-entries.html index 690930091..b3a41ae72 100644 --- a/src/addon/blog/components/entries/addon-blog-entries.html +++ b/src/addon/blog/components/entries/addon-blog-entries.html @@ -4,9 +4,9 @@
- + {{ 'addon.blog.showonlyyourentries' | translate }} - + >
diff --git a/src/addon/blog/components/entries/entries.ts b/src/addon/blog/components/entries/entries.ts index 071e53fe6..89a5b0917 100644 --- a/src/addon/blog/components/entries/entries.ts +++ b/src/addon/blog/components/entries/entries.ts @@ -15,6 +15,7 @@ import { Component, Input, OnInit, ViewChild } from '@angular/core'; import { Content } from 'ionic-angular'; import { CoreDomUtilsProvider } from '@providers/utils/dom'; +import { CoreUtilsProvider } from '@providers/utils/utils'; import { CoreSitesProvider } from '@providers/sites'; import { CoreUserProvider } from '@core/user/providers/user'; import { AddonBlogProvider } from '../../providers/blog'; @@ -38,6 +39,9 @@ export class AddonBlogEntriesComponent implements OnInit { protected filter = {}; protected pageLoaded = 0; + protected userPageLoaded = 0; + protected canLoadMoreEntries = false; + protected canLoadMoreUserEntries = true; @ViewChild(Content) content: Content; @@ -46,14 +50,14 @@ export class AddonBlogEntriesComponent implements OnInit { loadMoreError = false; entries = []; currentUserId: number; - showMyIssuesToggle = false; + showMyEntriesToggle = false; onlyMyEntries = false; component = AddonBlogProvider.COMPONENT; commentsEnabled: boolean; tagsEnabled: boolean; constructor(protected blogProvider: AddonBlogProvider, protected domUtils: CoreDomUtilsProvider, - protected userProvider: CoreUserProvider, sitesProvider: CoreSitesProvider, + protected userProvider: CoreUserProvider, sitesProvider: CoreSitesProvider, protected utils: CoreUtilsProvider, protected commentsProvider: CoreCommentsProvider, private tagProvider: CoreTagProvider) { this.currentUserId = sitesProvider.getCurrentSiteUserId(); } @@ -65,6 +69,7 @@ export class AddonBlogEntriesComponent implements OnInit { if (this.userId) { this.filter['userid'] = this.userId; } + this.showMyEntriesToggle = !this.userId; if (this.courseId) { this.filter['courseid'] = this.courseId; @@ -107,9 +112,12 @@ export class AddonBlogEntriesComponent implements OnInit { if (refresh) { this.pageLoaded = 0; + this.userPageLoaded = 0; } - return this.blogProvider.getEntries(this.filter, this.pageLoaded).then((result) => { + const loadPage = this.onlyMyEntries ? this.userPageLoaded : this.pageLoaded; + + return this.blogProvider.getEntries(this.filter, loadPage).then((result) => { const promises = result.entries.map((entry) => { switch (entry.publishstate) { case 'draft': @@ -134,16 +142,25 @@ export class AddonBlogEntriesComponent implements OnInit { }); if (refresh) { - this.showMyIssuesToggle = false; this.entries = result.entries; } else { - this.entries = this.entries.concat(result.entries); + this.entries = this.utils.uniqueArray(this.entries.concat(result.entries), 'id').sort((a, b) => { + return b.created - a.created; + }); } - this.canLoadMore = result.totalentries > this.entries.length; - this.pageLoaded++; - - this.showMyIssuesToggle = !this.userId; + if (this.onlyMyEntries) { + const count = this.entries.filter((entry) => { + return entry.userid == this.currentUserId; + }).length; + this.canLoadMoreUserEntries = result.totalentries > count; + this.canLoadMore = this.canLoadMoreUserEntries; + this.userPageLoaded++; + } else { + this.canLoadMoreEntries = result.totalentries > this.entries.length; + this.canLoadMore = this.canLoadMoreEntries; + this.pageLoaded++; + } return Promise.all(promises); }).catch((message) => { @@ -154,6 +171,30 @@ export class AddonBlogEntriesComponent implements OnInit { }); } + /** + * Toggle between showing only my entries or not. + * + * @param {boolean} enabled If true, filter my entries. False otherwise. + */ + onlyMyEntriesToggleChanged(enabled: boolean): void { + if (enabled) { + const count = this.entries.filter((entry) => { + return entry.userid == this.currentUserId; + }).length; + this.userPageLoaded = Math.floor(count / AddonBlogProvider.ENTRIES_PER_PAGE); + this.filter['userid'] = this.currentUserId; + + if (count == 0 && this.canLoadMoreUserEntries) { + // First time but no entry loaded. Try to load some. + this.loadMore(); + } + } else { + delete this.filter['userid']; + } + + this.canLoadMore = enabled ? this.canLoadMoreUserEntries : this.canLoadMoreEntries; + } + /** * Function to load more entries. * @@ -178,7 +219,17 @@ export class AddonBlogEntriesComponent implements OnInit { promises.push(this.blogProvider.invalidateEntries(this.filter)); - Promise.all(promises).finally(() => { + if (this.showMyEntriesToggle) { + this.filter['userid'] = this.currentUserId; + promises.push(this.blogProvider.invalidateEntries(this.filter)); + + if (!this.showMyEntriesToggle) { + delete this.filter['userid']; + } + + } + + this.utils.allPromises(promises).finally(() => { this.fetchEntries(true).finally(() => { if (refresher) { refresher.complete();