From 145832c117215119edeecb87e3dc2ace504d2eda Mon Sep 17 00:00:00 2001 From: Patrick Michalina Date: Fri, 5 Jul 2019 12:46:42 -0500 Subject: [PATCH] fix(grid): better fullscreen on iOS devices (#171) --- .../common/grid/grid.component.html | 6 +- .../common/grid/grid.component.spec.ts | 136 +++++++++++------- .../common/grid/grid.component.ts | 52 +++---- .../ng-grid-list/common/grid/helpers.spec.ts | 19 +-- .../ng-grid-list/common/grid/helpers.ts | 6 - .../common/list/grid-list.component.scss | 3 - .../flosportsinc/ng-grid-list/karma.conf.js | 2 +- 7 files changed, 110 insertions(+), 114 deletions(-) diff --git a/projects/flosportsinc/ng-grid-list/common/grid/grid.component.html b/projects/flosportsinc/ng-grid-list/common/grid/grid.component.html index ff2ad947..692e8ee5 100644 --- a/projects/flosportsinc/ng-grid-list/common/grid/grid.component.html +++ b/projects/flosportsinc/ng-grid-list/common/grid/grid.component.html @@ -5,7 +5,7 @@
-
+
diff --git a/projects/flosportsinc/ng-grid-list/common/grid/grid.component.spec.ts b/projects/flosportsinc/ng-grid-list/common/grid/grid.component.spec.ts index 4a8e2207..bdd71fe3 100644 --- a/projects/flosportsinc/ng-grid-list/common/grid/grid.component.spec.ts +++ b/projects/flosportsinc/ng-grid-list/common/grid/grid.component.spec.ts @@ -1,9 +1,9 @@ -import { async, TestBed } from '@angular/core/testing' +import { async, TestBed, fakeAsync, tick, discardPeriodicTasks } from '@angular/core/testing' import { FloGridListViewComponent } from './grid.component' import { FloGridListModule } from '../ng-grid-list.module' import { DEFAULT_FLO_GRID_LIST_DEFAULT_VIEWCOUNT, DEFAULT_FLO_GRID_LIST_ASPECT_RATIO } from '../ng-grid-list.module.defaults' import { take } from 'rxjs/operators' -import { PLATFORM_ID, Component, NgModule, ChangeDetectorRef, Renderer2 } from '@angular/core' +import { PLATFORM_ID, Component, NgModule } from '@angular/core' import { By } from '@angular/platform-browser' import { FLO_GRID_LIST_MIN_COUNT, FLO_GRID_LIST_MAX_COUNT, FLO_GRID_LIST_OVERLAY_ENABLED, @@ -75,7 +75,10 @@ const setupCountSomeNoneTests = (count: number, items: any[] = []) => { sut.hoistInstance.count = count sut.hoistFixture.detectChanges() - return sut.instance.gridItemContainers.toArray() + return { + collection: sut.instance.gridItemContainers.toArray(), + sut + } } describe(FloGridListViewComponent.name, () => { @@ -145,6 +148,18 @@ describe(FloGridListViewComponent.name, () => { it('should expose setter function', () => testInputPropSetFunc('selectedId', 'setSelectedId', 'awesome-id')) }) + describe('fullscreen', () => { + it('no', () => { + const sut = createSut() + // tslint:disable-next-line: no-if-statement + if (window.outerHeight - window.innerHeight <= 1) { + expect(sut.instance.isFullscreen()).toEqual(true) + } else { + expect(sut.instance.isFullscreen()).toEqual(false) + } + }) + }) + describe('aspectRatio property', () => { it('should double bind', () => testInputProperty('aspectRatio', 0.5625)) it('should expose setter function', () => testInputPropSetFunc('aspectRatio', 'setAspectRatio', 0.5625)) @@ -158,20 +173,6 @@ describe(FloGridListViewComponent.name, () => { const sut = createSut().instance expect(TestBed.get(FLO_GRID_LIST_ASPECT_RATIO)).toEqual(DEFAULT_FLO_GRID_LIST_ASPECT_RATIO) }) - it('should get native', () => { - const sut = createSut().instance - expect(sut.getNativeAspectRatio()).toEqual(window.screen.height / window.screen.width) - }) - - it('should get native when orientation is landscape', () => { - const sut = createSut().instance - const { width, height } = (window).screen; - (window).screen = { width: 300, height: 400 } - expect(window.screen.height).toEqual(400) - expect(window.screen.width).toEqual(300) - expect(sut.getNativeAspectRatio()).toEqual(window.screen.width / window.screen.height); - (window).screen = { width, height } // reset window object - }) it('should run change detection on fullscreen change', () => { const sut = createSut() @@ -291,36 +292,42 @@ describe(FloGridListViewComponent.name, () => { }) describe('when count equals 1', () => { - it('should show 1 empty', () => { + it('should show 1 empty', fakeAsync(() => { const result = setupCountSomeNoneTests(1, []) - expect(result.length).toEqual(1) - expect(result[0].nativeElement.innerText).toEqual('EMPTY') - }) - it('should show 1 filled', () => { + tick(0) + result.sut.hoistFixture.detectChanges() + expect(result.collection.length).toEqual(1) + expect(result.collection[0].nativeElement.innerText).toEqual('EMPTY') + discardPeriodicTasks() + })) + it('should show 1 filled', fakeAsync(() => { const result = setupCountSomeNoneTests(1, [{ id: '1', value: 'SOME_VALUE' }]) - expect(result.length).toEqual(1) - expect(result[0].nativeElement.innerText).toEqual('SOME_VALUE') - }) + tick(0) + result.sut.hoistFixture.detectChanges() + expect(result.collection.length).toEqual(1) + expect(result.collection[0].nativeElement.innerText).toEqual('SOME_VALUE') + discardPeriodicTasks() + })) }) describe('when count equals 2', () => { it('should show 2 empty', () => { const result = setupCountSomeNoneTests(2, []) - expect(result.length).toEqual(2) - expect(result[0].nativeElement.innerText).toEqual('EMPTY') - expect(result[1].nativeElement.innerText).toEqual('EMPTY') + expect(result.collection.length).toEqual(2) + expect(result.collection[0].nativeElement.innerText).toEqual('EMPTY') + expect(result.collection[1].nativeElement.innerText).toEqual('EMPTY') }) it('should show 1 empty, 1 filled', () => { const result = setupCountSomeNoneTests(2, [undefined, { id: '1', value: 'SOME_VALUE' }]) - expect(result.length).toEqual(2) - expect(result[0].nativeElement.innerText).toEqual('EMPTY') - expect(result[1].nativeElement.innerText).toEqual('SOME_VALUE') + expect(result.collection.length).toEqual(2) + expect(result.collection[0].nativeElement.innerText).toEqual('EMPTY') + expect(result.collection[1].nativeElement.innerText).toEqual('SOME_VALUE') }) it('should show 2 filled', () => { const result = setupCountSomeNoneTests(2, [{ id: '1', value: 'SOME_VALUE_1' }, { id: '2', value: 'SOME_VALUE_2' }]) - expect(result.length).toEqual(2) - expect(result[0].nativeElement.innerText).toEqual('SOME_VALUE_1') - expect(result[1].nativeElement.innerText).toEqual('SOME_VALUE_2') + expect(result.collection.length).toEqual(2) + expect(result.collection[0].nativeElement.innerText).toEqual('SOME_VALUE_1') + expect(result.collection[1].nativeElement.innerText).toEqual('SOME_VALUE_2') }) }) @@ -482,37 +489,51 @@ describe(FloGridListViewComponent.name, () => { })] }).compileComponents() }) - it('should handle counts of 1', () => { + it('should handle counts of 1', fakeAsync(() => { const sut = createSut() sut.hoistInstance.items = [SAMPLE_ITEM_1] sut.instance.setCount(1) + tick(0) + sut.hoistFixture.detectChanges() expect(sut.instance.selectedIndex).toEqual(0) - }) - it('should handle counts of 2', () => { + discardPeriodicTasks() + })) + it('should handle counts of 2', fakeAsync(() => { const sut = createSut() sut.hoistInstance.items = [SAMPLE_ITEM_1] sut.instance.setCount(2) + tick(0) + sut.hoistFixture.detectChanges() expect(sut.instance.selectedIndex).toEqual(1) - }) - it('should handle counts of 3', () => { + discardPeriodicTasks() + })) + it('should handle counts of 3', fakeAsync(() => { const sut = createSut() sut.hoistInstance.items = [SAMPLE_ITEM_1] sut.instance.setCount(3) + tick(0) + sut.hoistFixture.detectChanges() expect(sut.instance.selectedIndex).toEqual(1) - }) - it('should handle counts of 4', () => { + discardPeriodicTasks() + })) + it('should handle counts of 4', fakeAsync(() => { const sut = createSut() sut.hoistInstance.items = [SAMPLE_ITEM_1] sut.instance.setCount(4) + tick(0) + sut.hoistFixture.detectChanges() expect(sut.instance.selectedIndex).toEqual(1) - }) - - it('should handle multi items w/ counts', () => { + discardPeriodicTasks() + })) + it('should handle multi items w/ counts', fakeAsync(() => { const sut = createSut() sut.hoistInstance.items = [SAMPLE_ITEM_1, SAMPLE_ITEM_2] sut.instance.setCount(4) + tick(0) + sut.hoistFixture.detectChanges() expect(sut.instance.selectedIndex).toEqual(2) - }) + discardPeriodicTasks() + })) }) }) @@ -672,26 +693,32 @@ describe(FloGridListViewComponent.name, () => { }) describe('findNextEmptyIndex', () => { - it('should return next index when in viewcount', () => { + it('should return next index when in viewcount', fakeAsync(() => { const sut = createSut() sut.instance.setCount(4) sut.hoistInstance.items = [SAMPLE_ITEM_1] + tick(0) expect(sut.instance.findNextEmptyIndex()).toEqual(1) - }) + discardPeriodicTasks() + })) - it('should return -1 when no index is next', () => { + it('should return -1 when no index is next', fakeAsync(() => { const sut = createSut() sut.instance.setCount(1) sut.hoistInstance.items = [SAMPLE_ITEM_1] + tick(0) expect(sut.instance.findNextEmptyIndex()).toEqual(-1) - }) + discardPeriodicTasks() + })) - it('should return -1 when out of bounds', () => { + it('should return -1 when out of bounds', fakeAsync(() => { const sut = createSut() sut.instance.setCount(2) sut.hoistInstance.items = [SAMPLE_ITEM_1, SAMPLE_ITEM_2] + tick(0) expect(sut.instance.findNextEmptyIndex()).toEqual(-1) - }) + discardPeriodicTasks() + })) }) describe('fillNextEmpty', () => { @@ -703,13 +730,16 @@ describe(FloGridListViewComponent.name, () => { expect(sut.hoistInstance.items[0]).toEqual(SAMPLE_ITEM_1) }) - it('should fill first empty', () => { + it('should fill first empty', fakeAsync(() => { const sut = createSut() sut.instance.setCount(4) sut.hoistInstance.items = [SAMPLE_ITEM_1] sut.instance.fillNextEmpty(SAMPLE_ITEM_2) + tick(0) + sut.hoistFixture.detectChanges() expect(sut.hoistInstance.items[1]).toEqual(SAMPLE_ITEM_2) - }) + discardPeriodicTasks() + })) }) describe('isItemInAnotherIndex', () => { diff --git a/projects/flosportsinc/ng-grid-list/common/grid/grid.component.ts b/projects/flosportsinc/ng-grid-list/common/grid/grid.component.ts index 2d1daadf..8beb831e 100644 --- a/projects/flosportsinc/ng-grid-list/common/grid/grid.component.ts +++ b/projects/flosportsinc/ng-grid-list/common/grid/grid.component.ts @@ -4,7 +4,7 @@ import { isPlatformServer, isPlatformBrowser } from '@angular/common' import { maybe, IMaybe } from 'typescript-monads' -import { chunk, swapItemsViaIndices } from './helpers' +import { swapItemsViaIndices } from './helpers' import { Subject, fromEvent, of, interval, merge, BehaviorSubject } from 'rxjs' import { map, startWith, mapTo, share, switchMapTo, tap, distinctUntilChanged, takeUntil, shareReplay } from 'rxjs/operators' import { FloGridListOverlayDirective, FloGridListItemNoneDirective, FloGridListItemSomeDirective } from './grid.directive' @@ -36,8 +36,8 @@ import { export interface IViewItem { readonly value?: T readonly hasValue: boolean - readonly flexBasis: string - readonly padTop: string + readonly flexBasis: number + readonly padTop: number readonly isShowingBorder: boolean readonly isSelected: boolean readonly isNotSelected: boolean @@ -318,9 +318,6 @@ export class FloGridListViewComponent implem } public readonly isFullscreen = () => isPlatformBrowser(this._platformId) ? 1 >= window.outerHeight - window.innerHeight : false - public readonly getNativeAspectRatio = () => window.screen.height > window.screen.width - ? window.screen.width / window.screen.height - : window.screen.height / window.screen.width get baseMaxWidth() { return this.maxheight / this.aspectRatio @@ -331,15 +328,17 @@ export class FloGridListViewComponent implem } get aspectRatioPercentage() { - return `${(this.isFullscreen() ? this.getNativeAspectRatio() : this.aspectRatio) * 100 + '%'}` + return this.aspectRatio * 100 } get top() { - return this.count === 2 - ? this.isIE11 + return this.isIE11 + ? this.count === 2 ? '25%' - : 'inherit' - : '0px' + : 0 + : this.count === 2 || this.isFullscreen() + ? 'inherit' + : 0 } private readonly viewItemSource = new BehaviorSubject>>([]) @@ -408,7 +407,6 @@ export class FloGridListViewComponent implem this._cdRef.markForCheck() } - // TODO: optimize! createViewItems = () => { const square = Math.ceil(Math.sqrt(this.count)) @@ -416,24 +414,18 @@ export class FloGridListViewComponent implem .fill(maybe()) .map((val, idx) => this.items[idx] ? maybe(this.items[idx]) : val) - return chunk(square, stub) - .reduce((acc, curr) => { - return [ - ...acc, - ...curr.map((value, itemIndex, arrb) => { - const isSelected = this.selectedIndex === acc.length + itemIndex - return { - hasValue: value.isSome(), - value: value.valueOrUndefined(), - flexBasis: arrb.length > 1 ? 100 / arrb.length + '%' : 100 / square + '%', - padTop: arrb.length > 1 ? 56.25 / arrb.length + '%' : 56.25 / square + '%', - isShowingBorder: isSelected && this.count > 1, - isSelected, - isNotSelected: !isSelected - } - }) - ] - }, [] as ReadonlyArray>) + return stub.map>((value, idx) => { + const isSelected = this.selectedIndex === idx + return { + hasValue: value.isSome(), + value: value.valueOrUndefined(), + flexBasis: 100 / square, + padTop: this.aspectRatioPercentage / square, + isShowingBorder: isSelected && this.count > 1, + isSelected, + isNotSelected: !isSelected + } + }) } update() { diff --git a/projects/flosportsinc/ng-grid-list/common/grid/helpers.spec.ts b/projects/flosportsinc/ng-grid-list/common/grid/helpers.spec.ts index c136fd86..e7e3faf6 100644 --- a/projects/flosportsinc/ng-grid-list/common/grid/helpers.spec.ts +++ b/projects/flosportsinc/ng-grid-list/common/grid/helpers.spec.ts @@ -1,4 +1,4 @@ -import { swapItemsViaIndices, chunk } from './helpers' +import { swapItemsViaIndices } from './helpers' const COLLECTION_1: ReadonlyArray = [{ prop: 1 }, { prop: 2 }, { prop: 3 }] @@ -27,20 +27,3 @@ describe(swapItemsViaIndices.name, () => { expect(sut[2]).toBeUndefined() }) }) - -describe('chunk utility function', () => { - it('should work', () => { - const sut = chunk(1, [{}, {}, {}, {}]) - expect(sut.length).toEqual(4) - }) - - it('should handle empty collection', () => { - const sut = chunk(2, [{}, {}, {}]) - expect(sut.length).toEqual(2) - }) - - it('should handle empty collection', () => { - const sut = chunk(1) - expect(sut.length).toEqual(0) - }) -}) diff --git a/projects/flosportsinc/ng-grid-list/common/grid/helpers.ts b/projects/flosportsinc/ng-grid-list/common/grid/helpers.ts index 7c21e45c..ec1fd5db 100644 --- a/projects/flosportsinc/ng-grid-list/common/grid/helpers.ts +++ b/projects/flosportsinc/ng-grid-list/common/grid/helpers.ts @@ -14,9 +14,3 @@ export const swapItemsViaIndices = return _cloned } - -export const chunk = (size: number, collection: ReadonlyArray = []) => - collection.reduce((acc, _, index) => - index % size === 0 - ? [...acc, collection.slice(index, index + size)] - : acc, []) diff --git a/projects/flosportsinc/ng-grid-list/common/list/grid-list.component.scss b/projects/flosportsinc/ng-grid-list/common/list/grid-list.component.scss index 89a6d1f2..e69de29b 100644 --- a/projects/flosportsinc/ng-grid-list/common/list/grid-list.component.scss +++ b/projects/flosportsinc/ng-grid-list/common/list/grid-list.component.scss @@ -1,3 +0,0 @@ -:host { - -} \ No newline at end of file diff --git a/projects/flosportsinc/ng-grid-list/karma.conf.js b/projects/flosportsinc/ng-grid-list/karma.conf.js index c2351c5f..46dc4252 100644 --- a/projects/flosportsinc/ng-grid-list/karma.conf.js +++ b/projects/flosportsinc/ng-grid-list/karma.conf.js @@ -2,6 +2,6 @@ const config = require('../../../src/karma.conf.shared') module.exports = config('../coverage/ng-grid-list')()({ statements: 100, lines: 100, - branches: 97, + branches: 95, functions: 100 })