diff options
author | 杨宇千 <crupest@outlook.com> | 2019-02-24 17:04:29 +0000 |
---|---|---|
committer | 杨宇千 <crupest@outlook.com> | 2019-02-24 17:04:29 +0000 |
commit | 472cfcb7281cf8ee9dd3f22639c1370f99f7db16 (patch) | |
tree | 545c805dbd163da10845dfc352a4b3fe8e5ec01b /Timeline/ClientApp | |
parent | 5e3896fee6b0d376cb7c3f1927596a8ed00e40e4 (diff) | |
parent | ad16dbe268984d639c4924fb8bb1e69e68c0fef7 (diff) | |
download | timeline-472cfcb7281cf8ee9dd3f22639c1370f99f7db16.tar.gz timeline-472cfcb7281cf8ee9dd3f22639c1370f99f7db16.tar.bz2 timeline-472cfcb7281cf8ee9dd3f22639c1370f99f7db16.zip |
Merged PR 9: Add entrance animation of todo item.
Add entrance animation of todo item.
Related work items: #5
Diffstat (limited to 'Timeline/ClientApp')
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 @@ -<mat-progress-bar *ngIf="!items" mode="indeterminate"></mat-progress-bar> +<mat-progress-bar *ngIf="!isLoadCompleted" mode="indeterminate"></mat-progress-bar> <mat-list> <mat-list-item *ngFor="let item of items; let i = index" style="height:unset;"> <div class="item-box" [class.first-item-box]="i === 0" [class.non-first-item-box]="i !== 0"> - <app-todo-item [class.align-self-bottom]="i === 0" [item]="item"></app-todo-item> + <app-todo-item @itemEnter [class.align-self-bottom]="i === 0" [item]="item"></app-todo-item> <div class="space"></div> <div class="sample-box" *ngIf="i === 0"> <div class="mat-caption sample-item"> 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<T>(data: T): Observable<T> { - return defer(() => Promise.resolve(data)); +function asyncArray<T>(data: T[]): Observable<T> { + return from(data).pipe(delay(0)); } describe('TodoListPageComponent', () => { @@ -29,22 +29,31 @@ describe('TodoListPageComponent', () => { beforeEach(async(() => { const todoListService: jasmine.SpyObj<TodoListService> = 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<WorkItem, string>(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<WorkItem[]> { + getWorkItemList(): Observable<WorkItem> { 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<WorkItemResult>(result.url, { headers: headers })), concatMap(result => this.getItemIconUrl(baseUrl, headers, result.fields[TodoListService.typeFieldName]).pipe( @@ -94,8 +94,7 @@ export class TodoListService { } ) ) - ), - toArray() + ) ); }) ); |