From 9dcde15871a9980782befb769ceed15dc6dd6bbc Mon Sep 17 00:00:00 2001 From: Dani Palou Date: Fri, 22 Jun 2018 11:32:58 +0200 Subject: [PATCH] MOBILE-2431 tabs: Fix calculate number of core-tabs --- src/addon/messages/pages/index/index.ts | 16 ++++ .../mod/assign/components/index/index.ts | 18 ++++ .../components/submission/submission.ts | 14 +++ .../submission-review/submission-review.ts | 14 +++ .../mod/feedback/components/index/index.ts | 23 ++++- .../mod/lesson/components/index/index.ts | 9 +- src/addon/mod/wiki/components/index/index.ts | 4 + src/components/tabs/tabs.ts | 88 +++++++++++++++---- src/core/course/pages/section/section.ts | 4 + .../courses/pages/my-overview/my-overview.ts | 16 ++++ 10 files changed, 188 insertions(+), 18 deletions(-) diff --git a/src/addon/messages/pages/index/index.ts b/src/addon/messages/pages/index/index.ts index c02d0691e..66010ab05 100644 --- a/src/addon/messages/pages/index/index.ts +++ b/src/addon/messages/pages/index/index.ts @@ -18,6 +18,7 @@ import { CoreEventsProvider } from '@providers/events'; import { CoreSitesProvider } from '@providers/sites'; import { AddonMessagesProvider } from '../../providers/messages'; import { CoreSplitViewComponent } from '@components/split-view/split-view'; +import { CoreTabsComponent } from '@components/tabs/tabs'; /** * Page that displays the messages index page. @@ -29,6 +30,7 @@ import { CoreSplitViewComponent } from '@components/split-view/split-view'; }) export class AddonMessagesIndexPage implements OnDestroy { @ViewChild(CoreSplitViewComponent) splitviewCtrl: CoreSplitViewComponent; + @ViewChild(CoreTabsComponent) tabsComponent: CoreTabsComponent; protected loadSplitViewObserver: any; protected siteId: string; @@ -61,6 +63,20 @@ export class AddonMessagesIndexPage implements OnDestroy { this.splitviewCtrl.push('AddonMessagesDiscussionPage', params); } + /** + * User entered the page. + */ + ionViewDidEnter(): void { + this.tabsComponent && this.tabsComponent.ionViewDidEnter(); + } + + /** + * User left the page. + */ + ionViewDidLeave(): void { + this.tabsComponent && this.tabsComponent.ionViewDidLeave(); + } + /** * Page destroyed. */ diff --git a/src/addon/mod/assign/components/index/index.ts b/src/addon/mod/assign/components/index/index.ts index 22b9888f8..d832848b2 100644 --- a/src/addon/mod/assign/components/index/index.ts +++ b/src/addon/mod/assign/components/index/index.ts @@ -273,6 +273,24 @@ export class AddonModAssignIndexComponent extends CoreCourseModuleMainActivityCo }); } + /** + * User entered the page that contains the component. + */ + ionViewDidEnter(): void { + super.ionViewDidEnter(); + + this.submissionComponent && this.submissionComponent.ionViewDidEnter(); + } + + /** + * User left the page that contains the component. + */ + ionViewDidLeave(): void { + super.ionViewDidLeave(); + + this.submissionComponent && this.submissionComponent.ionViewDidLeave(); + } + /** * Compares sync event data with current data to check if refresh content is needed. * diff --git a/src/addon/mod/assign/components/submission/submission.ts b/src/addon/mod/assign/components/submission/submission.ts index 14aebdaad..5e3bdd160 100644 --- a/src/addon/mod/assign/components/submission/submission.ts +++ b/src/addon/mod/assign/components/submission/submission.ts @@ -313,6 +313,20 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy { return Promise.resolve(false); } + /** + * User entered the page that contains the component. + */ + ionViewDidEnter(): void { + this.tabs && this.tabs.ionViewDidEnter(); + } + + /** + * User left the page that contains the component. + */ + ionViewDidLeave(): void { + this.tabs && this.tabs.ionViewDidLeave(); + } + /** * Invalidate and refresh data. * diff --git a/src/addon/mod/assign/pages/submission-review/submission-review.ts b/src/addon/mod/assign/pages/submission-review/submission-review.ts index 8fe64533d..d6e39b6cd 100644 --- a/src/addon/mod/assign/pages/submission-review/submission-review.ts +++ b/src/addon/mod/assign/pages/submission-review/submission-review.ts @@ -76,6 +76,20 @@ export class AddonModAssignSubmissionReviewPage implements OnInit { return this.submissionComponent.canLeave(); } + /** + * User entered the page. + */ + ionViewDidEnter(): void { + this.submissionComponent && this.submissionComponent.ionViewDidEnter(); + } + + /** + * User left the page. + */ + ionViewDidLeave(): void { + this.submissionComponent && this.submissionComponent.ionViewDidLeave(); + } + /** * Get the submission. * diff --git a/src/addon/mod/feedback/components/index/index.ts b/src/addon/mod/feedback/components/index/index.ts index 904b4d799..140f5a376 100644 --- a/src/addon/mod/feedback/components/index/index.ts +++ b/src/addon/mod/feedback/components/index/index.ts @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { Component, Input, Optional, Injector } from '@angular/core'; +import { Component, Input, Optional, Injector, ViewChild } from '@angular/core'; import { Content, NavController } from 'ionic-angular'; import { CoreGroupInfo, CoreGroupsProvider } from '@providers/groups'; import { CoreCourseModuleMainActivityComponent } from '@core/course/classes/main-activity-component'; @@ -21,6 +21,7 @@ import { AddonModFeedbackHelperProvider } from '../../providers/helper'; import { AddonModFeedbackOfflineProvider } from '../../providers/offline'; import { AddonModFeedbackSyncProvider } from '../../providers/sync'; import * as moment from 'moment'; +import { CoreTabsComponent } from '@components/tabs/tabs'; /** * Component that displays a feedback index page. @@ -30,6 +31,8 @@ import * as moment from 'moment'; templateUrl: 'addon-mod-feedback-index.html', }) export class AddonModFeedbackIndexComponent extends CoreCourseModuleMainActivityComponent { + @ViewChild(CoreTabsComponent) tabsComponent: CoreTabsComponent; + @Input() tab = 'overview'; @Input() group = 0; @@ -348,6 +351,24 @@ export class AddonModFeedbackIndexComponent extends CoreCourseModuleMainActivity this.navCtrl.push('AddonModFeedbackFormPage', stateParams); } + /** + * User entered the page that contains the component. + */ + ionViewDidEnter(): void { + super.ionViewDidEnter(); + + this.tabsComponent && this.tabsComponent.ionViewDidEnter(); + } + + /** + * User left the page that contains the component. + */ + ionViewDidLeave(): void { + super.ionViewDidLeave(); + + this.tabsComponent && this.tabsComponent.ionViewDidLeave(); + } + /** * Function to link implemented features. * diff --git a/src/addon/mod/lesson/components/index/index.ts b/src/addon/mod/lesson/components/index/index.ts index 9eb698e04..f29f1a4ce 100644 --- a/src/addon/mod/lesson/components/index/index.ts +++ b/src/addon/mod/lesson/components/index/index.ts @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { Component, Optional, Injector, Input } from '@angular/core'; +import { Component, Optional, Injector, Input, ViewChild } from '@angular/core'; import { Content, NavController } from 'ionic-angular'; import { CoreGroupsProvider, CoreGroupInfo } from '@providers/groups'; import { CoreTimeUtilsProvider } from '@providers/utils/time'; @@ -24,6 +24,7 @@ import { AddonModLessonOfflineProvider } from '../../providers/lesson-offline'; import { AddonModLessonSyncProvider } from '../../providers/lesson-sync'; import { AddonModLessonPrefetchHandler } from '../../providers/prefetch-handler'; import { CoreConstants } from '@core/constants'; +import { CoreTabsComponent } from '@components/tabs/tabs'; /** * Component that displays a lesson entry page. @@ -33,6 +34,8 @@ import { CoreConstants } from '@core/constants'; templateUrl: 'addon-mod-lesson-index.html', }) export class AddonModLessonIndexComponent extends CoreCourseModuleMainActivityComponent { + @ViewChild(CoreTabsComponent) tabsComponent: CoreTabsComponent; + @Input() group: number; // The group to display. @Input() action: string; // The "action" to display first. @@ -226,6 +229,8 @@ export class AddonModLessonIndexComponent extends CoreCourseModuleMainActivityCo ionViewDidEnter(): void { super.ionViewDidEnter(); + this.tabsComponent && this.tabsComponent.ionViewDidEnter(); + // Update data when we come back from the player since the status could have changed. if (this.hasPlayed) { this.hasPlayed = false; @@ -240,6 +245,8 @@ export class AddonModLessonIndexComponent extends CoreCourseModuleMainActivityCo ionViewDidLeave(): void { super.ionViewDidLeave(); + this.tabsComponent && this.tabsComponent.ionViewDidLeave(); + if (this.navCtrl.getActive().component.name == 'AddonModLessonPlayerPage') { this.hasPlayed = true; } diff --git a/src/addon/mod/wiki/components/index/index.ts b/src/addon/mod/wiki/components/index/index.ts index d38b4a56d..bf0116676 100644 --- a/src/addon/mod/wiki/components/index/index.ts +++ b/src/addon/mod/wiki/components/index/index.ts @@ -735,6 +735,8 @@ export class AddonModWikiIndexComponent extends CoreCourseModuleMainActivityComp ionViewDidEnter(): void { super.ionViewDidEnter(); + this.tabs && this.tabs.ionViewDidEnter(); + if (this.hasEdited) { this.hasEdited = false; this.showLoadingAndRefresh(true, false); @@ -747,6 +749,8 @@ export class AddonModWikiIndexComponent extends CoreCourseModuleMainActivityComp ionViewDidLeave(): void { super.ionViewDidLeave(); + this.tabs && this.tabs.ionViewDidLeave(); + if (this.navCtrl.getActive().component.name == 'AddonModWikiEditPage') { this.hasEdited = true; } diff --git a/src/components/tabs/tabs.ts b/src/components/tabs/tabs.ts index 2d772fcd7..502cc3e89 100644 --- a/src/components/tabs/tabs.ts +++ b/src/components/tabs/tabs.ts @@ -13,11 +13,12 @@ // limitations under the License. import { - Component, Input, Output, EventEmitter, OnInit, OnChanges, AfterViewInit, ViewChild, ElementRef, + Component, Input, Output, EventEmitter, OnInit, OnChanges, OnDestroy, AfterViewInit, ViewChild, ElementRef, SimpleChange } from '@angular/core'; import { CoreTabComponent } from './tab'; import { Content, Slides } from 'ionic-angular'; +import { CoreDomUtilsProvider } from '@providers/utils/dom'; /** * This component displays some tabs that usually share data between them. @@ -41,7 +42,7 @@ import { Content, Slides } from 'ionic-angular'; selector: 'core-tabs', templateUrl: 'core-tabs.html' }) -export class CoreTabsComponent implements OnInit, AfterViewInit, OnChanges { +export class CoreTabsComponent implements OnInit, AfterViewInit, OnChanges, OnDestroy { @Input() selectedIndex = 0; // Index of the tab to select. @Input() hideUntil = true; // Determine when should the contents be shown. @Input() parentScrollable = false; // Determine if the scroll should be in the parent content or the tab itself. @@ -66,8 +67,11 @@ export class CoreTabsComponent implements OnInit, AfterViewInit, OnChanges { protected tabBarHeight; protected tabBarElement: HTMLElement; // Host element. protected tabsShown = true; + protected resizeFunction; + protected isDestroyed = false; + protected isCurrentView = true; - constructor(element: ElementRef, protected content: Content) { + constructor(element: ElementRef, protected content: Content, protected domUtils: CoreDomUtilsProvider) { this.tabBarElement = element.nativeElement; } @@ -83,6 +87,10 @@ export class CoreTabsComponent implements OnInit, AfterViewInit, OnChanges { * View has been initialized. */ ngAfterViewInit(): void { + if (this.isDestroyed) { + return; + } + this.afterViewInitTriggered = true; if (!this.initialized && this.hideUntil) { @@ -90,10 +98,9 @@ export class CoreTabsComponent implements OnInit, AfterViewInit, OnChanges { this.initializeTabs(); } - window.addEventListener('resize', () => { - this.calculateMaxSlides(); - this.updateSlides(); - }); + this.resizeFunction = this.calculateSlides.bind(this); + + window.addEventListener('resize', this.resizeFunction); } /** @@ -110,6 +117,24 @@ export class CoreTabsComponent implements OnInit, AfterViewInit, OnChanges { } } + /** + * User entered the page that contains the component. + */ + ionViewDidEnter(): void { + this.isCurrentView = true; + + if (this.initialized) { + this.calculateSlides(); + } + } + + /** + * User left the page that contains the component. + */ + ionViewDidLeave(): void { + this.isCurrentView = false; + } + /** * Add a new tab if it isn't already in the list of tabs. * @@ -120,7 +145,7 @@ export class CoreTabsComponent implements OnInit, AfterViewInit, OnChanges { if (this.getIndex(tab) == -1) { this.tabs.push(tab); this.sortTabs(); - this.updateSlides(); + this.calculateSlides(); if (this.initialized && this.tabs.length > 1 && this.tabBarHeight == 0) { // Calculate the tabBarHeight again now that there is more than 1 tab and the bar will be seen. @@ -132,6 +157,21 @@ export class CoreTabsComponent implements OnInit, AfterViewInit, OnChanges { } } + /** + * Calculate slides. + */ + calculateSlides(): void { + if (!this.isCurrentView || !this.tabsShown) { + // Don't calculate if component isn't in current view, the calculations are wrong. + return; + } + + setTimeout(() => { + this.calculateMaxSlides(); + this.updateSlides(); + }); + } + /** * Calculate the tab bar height. */ @@ -204,9 +244,8 @@ export class CoreTabsComponent implements OnInit, AfterViewInit, OnChanges { } } - // Check which arrows should be shown - this.calculateMaxSlides(); - this.updateSlides(); + // Check which arrows should be shown. + this.calculateSlides(); this.initialized = true; } @@ -247,11 +286,16 @@ export class CoreTabsComponent implements OnInit, AfterViewInit, OnChanges { } protected calculateMaxSlides(): void { - if (this.slides && this.slides.renderedWidth) { - this.maxSlides = Math.floor(this.slides.renderedWidth / 120); + if (this.slides) { + const width = this.domUtils.getElementWidth(this.slides.getNativeElement()) || this.slides.renderedWidth; - return; + if (width) { + this.maxSlides = Math.floor(width / 120); + + return; + } } + this.maxSlides = 3; } @@ -290,6 +334,7 @@ export class CoreTabsComponent implements OnInit, AfterViewInit, OnChanges { } else if (!this.tabsShown && e.target.scrollTop < this.tabBarHeight) { this.tabBarElement.classList.remove('tabs-hidden'); this.tabsShown = true; + this.calculateSlides(); } } @@ -302,7 +347,7 @@ export class CoreTabsComponent implements OnInit, AfterViewInit, OnChanges { const index = this.getIndex(tab); this.tabs.splice(index, 1); - this.updateSlides(); + this.calculateSlides(); } /** @@ -365,6 +410,17 @@ export class CoreTabsComponent implements OnInit, AfterViewInit, OnChanges { * Function to call when the visibility of a tab has changed. */ tabVisibilityChanged(): void { - this.updateSlides(); + this.calculateSlides(); + } + + /** + * Component destroyed. + */ + ngOnDestroy(): void { + this.isDestroyed = true; + + if (this.resizeFunction) { + window.removeEventListener('resize', this.resizeFunction); + } } } diff --git a/src/core/course/pages/section/section.ts b/src/core/course/pages/section/section.ts index 29aa49ac0..492266caf 100644 --- a/src/core/course/pages/section/section.ts +++ b/src/core/course/pages/section/section.ts @@ -26,6 +26,7 @@ import { CoreCourseModulePrefetchDelegate } from '../../providers/module-prefetc import { CoreCourseOptionsDelegate, CoreCourseOptionsHandlerToDisplay } from '../../providers/options-delegate'; import { CoreCourseFormatComponent } from '../../components/format/format'; import { CoreCoursesProvider } from '@core/courses/providers/courses'; +import { CoreTabsComponent } from '@components/tabs/tabs'; /** * Page that displays the list of courses the user is enrolled in. @@ -38,6 +39,7 @@ import { CoreCoursesProvider } from '@core/courses/providers/courses'; export class CoreCourseSectionPage implements OnDestroy { @ViewChild(Content) content: Content; @ViewChild(CoreCourseFormatComponent) formatComponent: CoreCourseFormatComponent; + @ViewChild(CoreTabsComponent) tabsComponent: CoreTabsComponent; title: string; course: any; @@ -378,6 +380,7 @@ export class CoreCourseSectionPage implements OnDestroy { */ ionViewDidEnter(): void { this.formatComponent && this.formatComponent.ionViewDidEnter(); + this.tabsComponent && this.tabsComponent.ionViewDidEnter(); } /** @@ -385,5 +388,6 @@ export class CoreCourseSectionPage implements OnDestroy { */ ionViewDidLeave(): void { this.formatComponent && this.formatComponent.ionViewDidLeave(); + this.tabsComponent && this.tabsComponent.ionViewDidLeave(); } } diff --git a/src/core/courses/pages/my-overview/my-overview.ts b/src/core/courses/pages/my-overview/my-overview.ts index 7a35b75d1..a698ff34b 100644 --- a/src/core/courses/pages/my-overview/my-overview.ts +++ b/src/core/courses/pages/my-overview/my-overview.ts @@ -24,6 +24,7 @@ import { CoreCourseHelperProvider } from '@core/course/providers/helper'; import { CoreCourseOptionsDelegate } from '@core/course/providers/options-delegate'; import { CoreSiteHomeProvider } from '@core/sitehome/providers/sitehome'; import * as moment from 'moment'; +import { CoreTabsComponent } from '@components/tabs/tabs'; /** * Page that displays My Overview. @@ -34,6 +35,7 @@ import * as moment from 'moment'; templateUrl: 'my-overview.html', }) export class CoreCoursesMyOverviewPage implements OnDestroy { + @ViewChild(CoreTabsComponent) tabsComponent: CoreTabsComponent; @ViewChild('searchbar') searchbar: Searchbar; firstSelectedTab: number; @@ -113,6 +115,20 @@ export class CoreCoursesMyOverviewPage implements OnDestroy { }); } + /** + * User entered the page. + */ + ionViewDidEnter(): void { + this.tabsComponent && this.tabsComponent.ionViewDidEnter(); + } + + /** + * User left the page. + */ + ionViewDidLeave(): void { + this.tabsComponent && this.tabsComponent.ionViewDidLeave(); + } + /** * Fetch the timeline. *