From ad16dbe268984d639c4924fb8bb1e69e68c0fef7 Mon Sep 17 00:00:00 2001 From: crupest Date: Mon, 25 Feb 2019 00:40:27 +0800 Subject: Add entrance animation of todo item. --- .../todo-list-page/todo-list-page.component.html | 4 +- .../todo-list-page.component.spec.ts | 43 +++++++++++++--------- .../app/todo-list-page/todo-list-page.component.ts | 23 ++++++++++-- .../app/todo-list-page/todo-list.service.spec.ts | 5 ++- .../src/app/todo-list-page/todo-list.service.ts | 11 +++--- 5 files changed, 57 insertions(+), 29 deletions(-) diff --git a/Timeline/ClientApp/src/app/todo-list-page/todo-list-page.component.html b/Timeline/ClientApp/src/app/todo-list-page/todo-list-page.component.html index 505032a6..e8f5f30b 100644 --- a/Timeline/ClientApp/src/app/todo-list-page/todo-list-page.component.html +++ b/Timeline/ClientApp/src/app/todo-list-page/todo-list-page.component.html @@ -1,9 +1,9 @@ - +
- +
diff --git a/Timeline/ClientApp/src/app/todo-list-page/todo-list-page.component.spec.ts b/Timeline/ClientApp/src/app/todo-list-page/todo-list-page.component.spec.ts index aed32c9a..a757b2a5 100644 --- a/Timeline/ClientApp/src/app/todo-list-page/todo-list-page.component.spec.ts +++ b/Timeline/ClientApp/src/app/todo-list-page/todo-list-page.component.spec.ts @@ -1,23 +1,23 @@ import { Component, NO_ERRORS_SCHEMA } from '@angular/core'; import { async, ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testing'; -import { defer, Observable } from 'rxjs'; +import { Observable, from } from 'rxjs'; import { TodoListPageComponent } from './todo-list-page.component'; import { TodoListService, WorkItem } from './todo-list.service'; import { By } from '@angular/platform-browser'; +import { delay } from 'rxjs/operators'; +import { NoopAnimationsModule } from '@angular/platform-browser/animations'; @Component({ /* tslint:disable-next-line:component-selector*/ selector: 'mat-progress-bar', template: '' }) -class MatProgressBarStubComponent { +class MatProgressBarStubComponent {} -} - -function asyncData(data: T): Observable { - return defer(() => Promise.resolve(data)); +function asyncArray(data: T[]): Observable { + return from(data).pipe(delay(0)); } describe('TodoListPageComponent', () => { @@ -29,22 +29,31 @@ describe('TodoListPageComponent', () => { beforeEach(async(() => { const todoListService: jasmine.SpyObj = jasmine.createSpyObj('TodoListService', ['getWorkItemList']); - mockWorkItems = [{ - id: 0, title: 'Test title 1', isCompleted: true, detailUrl: 'https://test.org/workitems/0', iconUrl: 'https://test.org/icon/0' - }, { - id: 1, title: 'Test title 2', isCompleted: false, detailUrl: 'https://test.org/workitems/1', iconUrl: 'https://test.org/icon/1' - }]; + mockWorkItems = [ + { + id: 0, + title: 'Test title 1', + isCompleted: true, + detailUrl: 'https://test.org/workitems/0', + iconUrl: 'https://test.org/icon/0' + }, + { + id: 1, + title: 'Test title 2', + isCompleted: false, + detailUrl: 'https://test.org/workitems/1', + iconUrl: 'https://test.org/icon/1' + } + ]; - todoListService.getWorkItemList.and.returnValue(asyncData(mockWorkItems)); + todoListService.getWorkItemList.and.returnValue(asyncArray(mockWorkItems)); TestBed.configureTestingModule({ declarations: [TodoListPageComponent, MatProgressBarStubComponent], - providers: [ - { provide: TodoListService, useValue: todoListService } - ], + imports: [NoopAnimationsModule], + providers: [{ provide: TodoListService, useValue: todoListService }], schemas: [NO_ERRORS_SCHEMA] - }) - .compileComponents(); + }).compileComponents(); })); beforeEach(() => { diff --git a/Timeline/ClientApp/src/app/todo-list-page/todo-list-page.component.ts b/Timeline/ClientApp/src/app/todo-list-page/todo-list-page.component.ts index e58cca7d..b04d1300 100644 --- a/Timeline/ClientApp/src/app/todo-list-page/todo-list-page.component.ts +++ b/Timeline/ClientApp/src/app/todo-list-page/todo-list-page.component.ts @@ -1,19 +1,36 @@ import { Component, OnInit } from '@angular/core'; import { TodoListService, WorkItem } from './todo-list.service'; +import { trigger, transition, style, animate } from '@angular/animations'; @Component({ selector: 'app-todo-list-page', templateUrl: './todo-list-page.component.html', - styleUrls: ['./todo-list-page.component.css', './todo-list-color-block.css'] + styleUrls: ['./todo-list-page.component.css', './todo-list-color-block.css'], + animations: [ + trigger('itemEnter', [ + transition(':enter', [ + style({ + transform: 'translateX(-100%) translateX(-20px)' + }), + animate('400ms ease-out', style({ + transform: 'none' + })) + ]) + ]) + ] }) export class TodoListPageComponent implements OnInit { - items: WorkItem[]; + items: WorkItem[] = []; + isLoadCompleted = false; constructor(private todoService: TodoListService) { } ngOnInit() { - this.todoService.getWorkItemList().subscribe(result => this.items = result); + this.todoService.getWorkItemList().subscribe({ + next: result => this.items.push(result), + complete: () => { this.isLoadCompleted = true; } + }); } } diff --git a/Timeline/ClientApp/src/app/todo-list-page/todo-list.service.spec.ts b/Timeline/ClientApp/src/app/todo-list-page/todo-list.service.spec.ts index 70922623..49b7bbc4 100644 --- a/Timeline/ClientApp/src/app/todo-list-page/todo-list.service.spec.ts +++ b/Timeline/ClientApp/src/app/todo-list-page/todo-list.service.spec.ts @@ -5,6 +5,7 @@ import { TodoListService, WorkItem, AzureDevOpsAccessInfo, WiqlResult, WiqlWorkItemResult, WorkItemResult, WorkItemTypeResult } from './todo-list.service'; +import { toArray } from 'rxjs/operators'; describe('TodoListServiceService', () => { @@ -41,7 +42,7 @@ describe('TodoListServiceService', () => { const workItemTypeMap = new Map(Array.from(mockWorkItems, v => <[WorkItem, string]>[v, 'type' + v.id])); - service.getWorkItemList().subscribe(data => { + service.getWorkItemList().pipe(toArray()).subscribe(data => { expect(data).toEqual(mockWorkItems); }); @@ -87,5 +88,7 @@ describe('TodoListServiceService', () => { } }); } + + httpController.verify(); }); }); diff --git a/Timeline/ClientApp/src/app/todo-list-page/todo-list.service.ts b/Timeline/ClientApp/src/app/todo-list-page/todo-list.service.ts index af3617fe..bfeb3285 100644 --- a/Timeline/ClientApp/src/app/todo-list-page/todo-list.service.ts +++ b/Timeline/ClientApp/src/app/todo-list-page/todo-list.service.ts @@ -1,7 +1,7 @@ import { Injectable } from '@angular/core'; import { HttpClient, HttpHeaders } from '@angular/common/http'; -import { Observable } from 'rxjs'; -import { switchMap, concatMap, map, toArray } from 'rxjs/operators'; +import { Observable, from } from 'rxjs'; +import { switchMap, concatMap, map } from 'rxjs/operators'; export interface AzureDevOpsAccessInfo { username: string; @@ -60,7 +60,7 @@ export class TodoListService { .pipe(map(result => result.icon.url)); } - getWorkItemList(): Observable { + getWorkItemList(): Observable { return this.getAzureDevOpsAccessInfo().pipe( switchMap(accessInfo => { const baseUrl = `https://dev.azure.com/${accessInfo.organization}/${accessInfo.project}/`; @@ -77,7 +77,7 @@ export class TodoListService { { headers: headers } ) .pipe( - switchMap(result => result.workItems), + concatMap(result => from(result.workItems)), concatMap(result => this.client.get(result.url, { headers: headers })), concatMap(result => this.getItemIconUrl(baseUrl, headers, result.fields[TodoListService.typeFieldName]).pipe( @@ -94,8 +94,7 @@ export class TodoListService { } ) ) - ), - toArray() + ) ); }) ); -- cgit v1.2.3