MOBILE-2431 tabs: Fix calculate number of core-tabs

main
Dani Palou 2018-06-22 11:32:58 +02:00
parent 668c36cd43
commit 9dcde15871
10 changed files with 188 additions and 18 deletions

View File

@ -18,6 +18,7 @@ import { CoreEventsProvider } from '@providers/events';
import { CoreSitesProvider } from '@providers/sites'; import { CoreSitesProvider } from '@providers/sites';
import { AddonMessagesProvider } from '../../providers/messages'; import { AddonMessagesProvider } from '../../providers/messages';
import { CoreSplitViewComponent } from '@components/split-view/split-view'; import { CoreSplitViewComponent } from '@components/split-view/split-view';
import { CoreTabsComponent } from '@components/tabs/tabs';
/** /**
* Page that displays the messages index page. * Page that displays the messages index page.
@ -29,6 +30,7 @@ import { CoreSplitViewComponent } from '@components/split-view/split-view';
}) })
export class AddonMessagesIndexPage implements OnDestroy { export class AddonMessagesIndexPage implements OnDestroy {
@ViewChild(CoreSplitViewComponent) splitviewCtrl: CoreSplitViewComponent; @ViewChild(CoreSplitViewComponent) splitviewCtrl: CoreSplitViewComponent;
@ViewChild(CoreTabsComponent) tabsComponent: CoreTabsComponent;
protected loadSplitViewObserver: any; protected loadSplitViewObserver: any;
protected siteId: string; protected siteId: string;
@ -61,6 +63,20 @@ export class AddonMessagesIndexPage implements OnDestroy {
this.splitviewCtrl.push('AddonMessagesDiscussionPage', params); 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. * Page destroyed.
*/ */

View File

@ -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. * Compares sync event data with current data to check if refresh content is needed.
* *

View File

@ -313,6 +313,20 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy {
return Promise.resolve(false); 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. * Invalidate and refresh data.
* *

View File

@ -76,6 +76,20 @@ export class AddonModAssignSubmissionReviewPage implements OnInit {
return this.submissionComponent.canLeave(); 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. * Get the submission.
* *

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, Input, Optional, Injector } from '@angular/core'; import { Component, Input, Optional, Injector, ViewChild } from '@angular/core';
import { Content, NavController } from 'ionic-angular'; import { Content, NavController } from 'ionic-angular';
import { CoreGroupInfo, CoreGroupsProvider } from '@providers/groups'; import { CoreGroupInfo, CoreGroupsProvider } from '@providers/groups';
import { CoreCourseModuleMainActivityComponent } from '@core/course/classes/main-activity-component'; import { CoreCourseModuleMainActivityComponent } from '@core/course/classes/main-activity-component';
@ -21,6 +21,7 @@ import { AddonModFeedbackHelperProvider } from '../../providers/helper';
import { AddonModFeedbackOfflineProvider } from '../../providers/offline'; import { AddonModFeedbackOfflineProvider } from '../../providers/offline';
import { AddonModFeedbackSyncProvider } from '../../providers/sync'; import { AddonModFeedbackSyncProvider } from '../../providers/sync';
import * as moment from 'moment'; import * as moment from 'moment';
import { CoreTabsComponent } from '@components/tabs/tabs';
/** /**
* Component that displays a feedback index page. * Component that displays a feedback index page.
@ -30,6 +31,8 @@ import * as moment from 'moment';
templateUrl: 'addon-mod-feedback-index.html', templateUrl: 'addon-mod-feedback-index.html',
}) })
export class AddonModFeedbackIndexComponent extends CoreCourseModuleMainActivityComponent { export class AddonModFeedbackIndexComponent extends CoreCourseModuleMainActivityComponent {
@ViewChild(CoreTabsComponent) tabsComponent: CoreTabsComponent;
@Input() tab = 'overview'; @Input() tab = 'overview';
@Input() group = 0; @Input() group = 0;
@ -348,6 +351,24 @@ export class AddonModFeedbackIndexComponent extends CoreCourseModuleMainActivity
this.navCtrl.push('AddonModFeedbackFormPage', stateParams); 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. * Function to link implemented features.
* *

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, Optional, Injector, Input } from '@angular/core'; import { Component, Optional, Injector, Input, ViewChild } from '@angular/core';
import { Content, NavController } from 'ionic-angular'; import { Content, NavController } from 'ionic-angular';
import { CoreGroupsProvider, CoreGroupInfo } from '@providers/groups'; import { CoreGroupsProvider, CoreGroupInfo } from '@providers/groups';
import { CoreTimeUtilsProvider } from '@providers/utils/time'; import { CoreTimeUtilsProvider } from '@providers/utils/time';
@ -24,6 +24,7 @@ import { AddonModLessonOfflineProvider } from '../../providers/lesson-offline';
import { AddonModLessonSyncProvider } from '../../providers/lesson-sync'; import { AddonModLessonSyncProvider } from '../../providers/lesson-sync';
import { AddonModLessonPrefetchHandler } from '../../providers/prefetch-handler'; import { AddonModLessonPrefetchHandler } from '../../providers/prefetch-handler';
import { CoreConstants } from '@core/constants'; import { CoreConstants } from '@core/constants';
import { CoreTabsComponent } from '@components/tabs/tabs';
/** /**
* Component that displays a lesson entry page. * Component that displays a lesson entry page.
@ -33,6 +34,8 @@ import { CoreConstants } from '@core/constants';
templateUrl: 'addon-mod-lesson-index.html', templateUrl: 'addon-mod-lesson-index.html',
}) })
export class AddonModLessonIndexComponent extends CoreCourseModuleMainActivityComponent { export class AddonModLessonIndexComponent extends CoreCourseModuleMainActivityComponent {
@ViewChild(CoreTabsComponent) tabsComponent: CoreTabsComponent;
@Input() group: number; // The group to display. @Input() group: number; // The group to display.
@Input() action: string; // The "action" to display first. @Input() action: string; // The "action" to display first.
@ -226,6 +229,8 @@ export class AddonModLessonIndexComponent extends CoreCourseModuleMainActivityCo
ionViewDidEnter(): void { ionViewDidEnter(): void {
super.ionViewDidEnter(); super.ionViewDidEnter();
this.tabsComponent && this.tabsComponent.ionViewDidEnter();
// Update data when we come back from the player since the status could have changed. // Update data when we come back from the player since the status could have changed.
if (this.hasPlayed) { if (this.hasPlayed) {
this.hasPlayed = false; this.hasPlayed = false;
@ -240,6 +245,8 @@ export class AddonModLessonIndexComponent extends CoreCourseModuleMainActivityCo
ionViewDidLeave(): void { ionViewDidLeave(): void {
super.ionViewDidLeave(); super.ionViewDidLeave();
this.tabsComponent && this.tabsComponent.ionViewDidLeave();
if (this.navCtrl.getActive().component.name == 'AddonModLessonPlayerPage') { if (this.navCtrl.getActive().component.name == 'AddonModLessonPlayerPage') {
this.hasPlayed = true; this.hasPlayed = true;
} }

View File

@ -735,6 +735,8 @@ export class AddonModWikiIndexComponent extends CoreCourseModuleMainActivityComp
ionViewDidEnter(): void { ionViewDidEnter(): void {
super.ionViewDidEnter(); super.ionViewDidEnter();
this.tabs && this.tabs.ionViewDidEnter();
if (this.hasEdited) { if (this.hasEdited) {
this.hasEdited = false; this.hasEdited = false;
this.showLoadingAndRefresh(true, false); this.showLoadingAndRefresh(true, false);
@ -747,6 +749,8 @@ export class AddonModWikiIndexComponent extends CoreCourseModuleMainActivityComp
ionViewDidLeave(): void { ionViewDidLeave(): void {
super.ionViewDidLeave(); super.ionViewDidLeave();
this.tabs && this.tabs.ionViewDidLeave();
if (this.navCtrl.getActive().component.name == 'AddonModWikiEditPage') { if (this.navCtrl.getActive().component.name == 'AddonModWikiEditPage') {
this.hasEdited = true; this.hasEdited = true;
} }

View File

@ -13,11 +13,12 @@
// limitations under the License. // limitations under the License.
import { import {
Component, Input, Output, EventEmitter, OnInit, OnChanges, AfterViewInit, ViewChild, ElementRef, Component, Input, Output, EventEmitter, OnInit, OnChanges, OnDestroy, AfterViewInit, ViewChild, ElementRef,
SimpleChange SimpleChange
} from '@angular/core'; } from '@angular/core';
import { CoreTabComponent } from './tab'; import { CoreTabComponent } from './tab';
import { Content, Slides } from 'ionic-angular'; import { Content, Slides } from 'ionic-angular';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
/** /**
* This component displays some tabs that usually share data between them. * This component displays some tabs that usually share data between them.
@ -41,7 +42,7 @@ import { Content, Slides } from 'ionic-angular';
selector: 'core-tabs', selector: 'core-tabs',
templateUrl: 'core-tabs.html' 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() selectedIndex = 0; // Index of the tab to select.
@Input() hideUntil = true; // Determine when should the contents be shown. @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. @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 tabBarHeight;
protected tabBarElement: HTMLElement; // Host element. protected tabBarElement: HTMLElement; // Host element.
protected tabsShown = true; 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; this.tabBarElement = element.nativeElement;
} }
@ -83,6 +87,10 @@ export class CoreTabsComponent implements OnInit, AfterViewInit, OnChanges {
* View has been initialized. * View has been initialized.
*/ */
ngAfterViewInit(): void { ngAfterViewInit(): void {
if (this.isDestroyed) {
return;
}
this.afterViewInitTriggered = true; this.afterViewInitTriggered = true;
if (!this.initialized && this.hideUntil) { if (!this.initialized && this.hideUntil) {
@ -90,10 +98,9 @@ export class CoreTabsComponent implements OnInit, AfterViewInit, OnChanges {
this.initializeTabs(); this.initializeTabs();
} }
window.addEventListener('resize', () => { this.resizeFunction = this.calculateSlides.bind(this);
this.calculateMaxSlides();
this.updateSlides(); 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. * 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) { if (this.getIndex(tab) == -1) {
this.tabs.push(tab); this.tabs.push(tab);
this.sortTabs(); this.sortTabs();
this.updateSlides(); this.calculateSlides();
if (this.initialized && this.tabs.length > 1 && this.tabBarHeight == 0) { 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. // 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. * Calculate the tab bar height.
*/ */
@ -204,9 +244,8 @@ export class CoreTabsComponent implements OnInit, AfterViewInit, OnChanges {
} }
} }
// Check which arrows should be shown // Check which arrows should be shown.
this.calculateMaxSlides(); this.calculateSlides();
this.updateSlides();
this.initialized = true; this.initialized = true;
} }
@ -247,11 +286,16 @@ export class CoreTabsComponent implements OnInit, AfterViewInit, OnChanges {
} }
protected calculateMaxSlides(): void { protected calculateMaxSlides(): void {
if (this.slides && this.slides.renderedWidth) { if (this.slides) {
this.maxSlides = Math.floor(this.slides.renderedWidth / 120); const width = this.domUtils.getElementWidth(this.slides.getNativeElement()) || this.slides.renderedWidth;
return; if (width) {
this.maxSlides = Math.floor(width / 120);
return;
}
} }
this.maxSlides = 3; this.maxSlides = 3;
} }
@ -290,6 +334,7 @@ export class CoreTabsComponent implements OnInit, AfterViewInit, OnChanges {
} else if (!this.tabsShown && e.target.scrollTop < this.tabBarHeight) { } else if (!this.tabsShown && e.target.scrollTop < this.tabBarHeight) {
this.tabBarElement.classList.remove('tabs-hidden'); this.tabBarElement.classList.remove('tabs-hidden');
this.tabsShown = true; this.tabsShown = true;
this.calculateSlides();
} }
} }
@ -302,7 +347,7 @@ export class CoreTabsComponent implements OnInit, AfterViewInit, OnChanges {
const index = this.getIndex(tab); const index = this.getIndex(tab);
this.tabs.splice(index, 1); 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. * Function to call when the visibility of a tab has changed.
*/ */
tabVisibilityChanged(): void { tabVisibilityChanged(): void {
this.updateSlides(); this.calculateSlides();
}
/**
* Component destroyed.
*/
ngOnDestroy(): void {
this.isDestroyed = true;
if (this.resizeFunction) {
window.removeEventListener('resize', this.resizeFunction);
}
} }
} }

View File

@ -26,6 +26,7 @@ import { CoreCourseModulePrefetchDelegate } from '../../providers/module-prefetc
import { CoreCourseOptionsDelegate, CoreCourseOptionsHandlerToDisplay } from '../../providers/options-delegate'; import { CoreCourseOptionsDelegate, CoreCourseOptionsHandlerToDisplay } from '../../providers/options-delegate';
import { CoreCourseFormatComponent } from '../../components/format/format'; import { CoreCourseFormatComponent } from '../../components/format/format';
import { CoreCoursesProvider } from '@core/courses/providers/courses'; 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. * 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 { export class CoreCourseSectionPage implements OnDestroy {
@ViewChild(Content) content: Content; @ViewChild(Content) content: Content;
@ViewChild(CoreCourseFormatComponent) formatComponent: CoreCourseFormatComponent; @ViewChild(CoreCourseFormatComponent) formatComponent: CoreCourseFormatComponent;
@ViewChild(CoreTabsComponent) tabsComponent: CoreTabsComponent;
title: string; title: string;
course: any; course: any;
@ -378,6 +380,7 @@ export class CoreCourseSectionPage implements OnDestroy {
*/ */
ionViewDidEnter(): void { ionViewDidEnter(): void {
this.formatComponent && this.formatComponent.ionViewDidEnter(); this.formatComponent && this.formatComponent.ionViewDidEnter();
this.tabsComponent && this.tabsComponent.ionViewDidEnter();
} }
/** /**
@ -385,5 +388,6 @@ export class CoreCourseSectionPage implements OnDestroy {
*/ */
ionViewDidLeave(): void { ionViewDidLeave(): void {
this.formatComponent && this.formatComponent.ionViewDidLeave(); this.formatComponent && this.formatComponent.ionViewDidLeave();
this.tabsComponent && this.tabsComponent.ionViewDidLeave();
} }
} }

View File

@ -24,6 +24,7 @@ import { CoreCourseHelperProvider } from '@core/course/providers/helper';
import { CoreCourseOptionsDelegate } from '@core/course/providers/options-delegate'; import { CoreCourseOptionsDelegate } from '@core/course/providers/options-delegate';
import { CoreSiteHomeProvider } from '@core/sitehome/providers/sitehome'; import { CoreSiteHomeProvider } from '@core/sitehome/providers/sitehome';
import * as moment from 'moment'; import * as moment from 'moment';
import { CoreTabsComponent } from '@components/tabs/tabs';
/** /**
* Page that displays My Overview. * Page that displays My Overview.
@ -34,6 +35,7 @@ import * as moment from 'moment';
templateUrl: 'my-overview.html', templateUrl: 'my-overview.html',
}) })
export class CoreCoursesMyOverviewPage implements OnDestroy { export class CoreCoursesMyOverviewPage implements OnDestroy {
@ViewChild(CoreTabsComponent) tabsComponent: CoreTabsComponent;
@ViewChild('searchbar') searchbar: Searchbar; @ViewChild('searchbar') searchbar: Searchbar;
firstSelectedTab: number; 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. * Fetch the timeline.
* *