aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2019-02-25 00:40:27 +0800
committercrupest <crupest@outlook.com>2019-02-25 00:40:27 +0800
commitad16dbe268984d639c4924fb8bb1e69e68c0fef7 (patch)
tree545c805dbd163da10845dfc352a4b3fe8e5ec01b
parent5e3896fee6b0d376cb7c3f1927596a8ed00e40e4 (diff)
downloadtimeline-ad16dbe268984d639c4924fb8bb1e69e68c0fef7.tar.gz
timeline-ad16dbe268984d639c4924fb8bb1e69e68c0fef7.tar.bz2
timeline-ad16dbe268984d639c4924fb8bb1e69e68c0fef7.zip
Add entrance animation of todo item.
-rw-r--r--Timeline/ClientApp/src/app/todo-list-page/todo-list-page.component.html4
-rw-r--r--Timeline/ClientApp/src/app/todo-list-page/todo-list-page.component.spec.ts43
-rw-r--r--Timeline/ClientApp/src/app/todo-list-page/todo-list-page.component.ts23
-rw-r--r--Timeline/ClientApp/src/app/todo-list-page/todo-list.service.spec.ts5
-rw-r--r--Timeline/ClientApp/src/app/todo-list-page/todo-list.service.ts11
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()
+ )
);
})
);