Skip to content

Commit d9731b1

Browse files
Feature metadata dialogue (#52)
* add information page * add importance and type attributes to info interface Co-authored-by: Sean Wu <seanwu1105@gmail.com>
1 parent 9317f84 commit d9731b1

File tree

12 files changed

+283
-29
lines changed

12 files changed

+283
-29
lines changed

src/app/app-routing.module.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ const routes: Routes = [{
1414
}, {
1515
path: 'proof',
1616
loadChildren: () => import('./pages/proof/proof.module').then(m => m.ProofPageModule)
17+
}, {
18+
path: 'information',
19+
loadChildren: () => import('./pages/information/information.module').then(m => m.InformationPageModule)
1720
}];
1821

1922
@NgModule({
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { NgModule } from '@angular/core';
2+
import { RouterModule, Routes } from '@angular/router';
3+
import { InformationPage } from './information.page';
4+
5+
const routes: Routes = [{
6+
path: '',
7+
component: InformationPage
8+
}];
9+
10+
@NgModule({
11+
imports: [RouterModule.forChild(routes)],
12+
exports: [RouterModule],
13+
})
14+
export class InformationPageRoutingModule { }
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { CommonModule } from '@angular/common';
2+
import { NgModule } from '@angular/core';
3+
import { FormsModule } from '@angular/forms';
4+
import { IonicModule } from '@ionic/angular';
5+
import { TranslocoModule } from '@ngneat/transloco';
6+
import { InformationPageRoutingModule } from './information-routing.module';
7+
import { InformationPage } from './information.page';
8+
9+
@NgModule({
10+
imports: [
11+
CommonModule,
12+
FormsModule,
13+
IonicModule,
14+
InformationPageRoutingModule,
15+
TranslocoModule
16+
],
17+
declarations: [InformationPage]
18+
})
19+
export class InformationPageModule { }
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
<ion-header *transloco="let t">
2+
<ion-toolbar>
3+
<ion-buttons slot="start">
4+
<ion-button [routerLink]="['/proof', {hash: (hash$ | async)}]" routerDirection="back">
5+
<ion-icon slot="icon-only" name="arrow-back"></ion-icon>
6+
</ion-button>
7+
</ion-buttons>
8+
<ion-title>{{ t('informationDetails') }}</ion-title>
9+
</ion-toolbar>
10+
</ion-header>
11+
<ion-content *transloco="let t">
12+
<ion-item>
13+
<ion-slide>
14+
<ion-card class="slide-card">
15+
<ion-card-header>
16+
<ion-card-title>{{ t('location') }}</ion-card-title>
17+
</ion-card-header>
18+
<ion-card-content>
19+
<ion-list lines="none" *ngFor="let information of (locationInformation$ | async)">
20+
<ion-item>
21+
<ion-label class="ion-text-wrap">
22+
<h3>{{ information.name }}</h3>
23+
<p>{{ information.value }}</p>
24+
</ion-label>
25+
</ion-item>
26+
</ion-list>
27+
</ion-card-content>
28+
</ion-card>
29+
</ion-slide>
30+
</ion-item>
31+
<ion-item>
32+
<ion-slide>
33+
<ion-card class="slide-card">
34+
<ion-card-header>
35+
<ion-card-title>{{ t('other') }}</ion-card-title>
36+
</ion-card-header>
37+
<ion-card-content>
38+
<ion-list lines="none" *ngFor="let information of (otherInformation$ | async)">
39+
<ion-item>
40+
<ion-label class="ion-text-wrap">
41+
<h3>{{ information.name }}</h3>
42+
<p>{{ information.value }}</p>
43+
</ion-label>
44+
</ion-item>
45+
</ion-list>
46+
</ion-card-content>
47+
</ion-card>
48+
</ion-slide>
49+
</ion-item>
50+
<ion-item>
51+
<ion-slide>
52+
<ion-card class="slide-card">
53+
<ion-card-header>
54+
<ion-card-title>{{ t('device') }}</ion-card-title>
55+
</ion-card-header>
56+
<ion-card-content>
57+
<ion-list lines="none" *ngFor="let information of (deviceInformation$ | async)">
58+
<ion-item>
59+
<ion-label class="ion-text-wrap">
60+
<h3>{{ information.name }}</h3>
61+
<p>{{ information.value }}</p>
62+
</ion-label>
63+
</ion-item>
64+
</ion-list>
65+
</ion-card-content>
66+
</ion-card>
67+
</ion-slide>
68+
</ion-item>
69+
</ion-content>
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
.slide-card {
2+
width: 100%;
3+
}
4+
5+
.multiline {
6+
white-space: pre-wrap;
7+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
2+
import { RouterTestingModule } from '@angular/router/testing';
3+
import { IonicModule } from '@ionic/angular';
4+
import { getTranslocoModule } from 'src/app/transloco/transloco-root.module.spec';
5+
import { InformationPage } from './information.page';
6+
7+
describe('InformationPage', () => {
8+
let component: InformationPage;
9+
let fixture: ComponentFixture<InformationPage>;
10+
11+
beforeEach(async(() => {
12+
TestBed.configureTestingModule({
13+
declarations: [InformationPage],
14+
imports: [IonicModule.forRoot(), RouterTestingModule, getTranslocoModule()]
15+
}).compileComponents();
16+
17+
fixture = TestBed.createComponent(InformationPage);
18+
component = fixture.componentInstance;
19+
fixture.detectChanges();
20+
}));
21+
22+
it('should create', () => {
23+
expect(component).toBeTruthy();
24+
});
25+
});
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import { Component } from '@angular/core';
2+
import { ActivatedRoute } from '@angular/router';
3+
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
4+
import { map, pluck, switchMap, switchMapTo } from 'rxjs/operators';
5+
import { InformationType } from 'src/app/services/data/information/information';
6+
import { InformationRepository } from 'src/app/services/data/information/information-repository.service';
7+
import { ProofRepository } from 'src/app/services/data/proof/proof-repository.service';
8+
import { isNonNullable } from 'src/app/utils/rx-operators';
9+
10+
@UntilDestroy({ checkProperties: true })
11+
@Component({
12+
selector: 'app-information',
13+
templateUrl: './information.page.html',
14+
styleUrls: ['./information.page.scss'],
15+
})
16+
export class InformationPage {
17+
18+
readonly proof$ = this.route.paramMap.pipe(
19+
map(params => params.get('hash')),
20+
isNonNullable(),
21+
switchMap(hash => this.proofRepository.getByHash$(hash)),
22+
isNonNullable()
23+
);
24+
25+
readonly hash$ = this.proof$.pipe(pluck('hash'));
26+
27+
readonly locationInformation$ = this.proof$.pipe(
28+
switchMap(proof => this.informationRepository.getByProof$(proof)),
29+
map(informationList => informationList.filter(information => information.type === InformationType.Location))
30+
);
31+
32+
readonly otherInformation$ = this.proof$.pipe(
33+
switchMap(proof => this.informationRepository.getByProof$(proof)),
34+
map(informationList => informationList.filter(information => information.type === InformationType.Other))
35+
);
36+
37+
readonly deviceInformation$ = this.proof$.pipe(
38+
switchMap(proof => this.informationRepository.getByProof$(proof)),
39+
map(informationList => informationList.filter(information => information.type === InformationType.Device))
40+
);
41+
42+
constructor(
43+
private readonly route: ActivatedRoute,
44+
private readonly proofRepository: ProofRepository,
45+
private readonly informationRepository: InformationRepository,
46+
) { }
47+
48+
ionViewWillEnter() {
49+
this.proofRepository.refresh$().pipe(
50+
switchMapTo(this.informationRepository.refresh$()),
51+
untilDestroyed(this)
52+
).subscribe();
53+
}
54+
}

src/app/pages/proof/proof.page.html

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<ion-header *transloco="let t">
22
<ion-toolbar>
33
<ion-buttons slot="start">
4-
<ion-button routerLink=".." routerDirection="back">
4+
<ion-button [routerLink]="['/storage']" routerDirection="back">
55
<ion-icon slot="icon-only" name="arrow-back"></ion-icon>
66
</ion-button>
77
</ion-buttons>
@@ -58,20 +58,25 @@ <h2>{{ t('information') }}</h2>
5858
</ion-list-header>
5959
<ion-item>
6060
<ion-slides pager>
61-
<ion-slide *ngFor="let providerWithInformationList of (providersWithInformationList$ | async)">
62-
<ion-card class="slide-card">
61+
<ion-slide>
62+
<ion-card class="slide-card"
63+
*ngFor="let providerWithInformationList of (providersWithImportantInformation$ | async)">
6364
<ion-card-header>
6465
<ion-card-title>{{ providerWithInformationList.provider }}</ion-card-title>
6566
</ion-card-header>
6667
<ion-card-content>
67-
<ion-list>
68-
<ion-item *ngFor="let information of providerWithInformationList.informationList">
68+
<ion-list *ngFor="let information of providerWithInformationList.informationList">
69+
<ion-item>
6970
<ion-label class="ion-text-wrap">
7071
<h3>{{ information.name }}</h3>
7172
<p>{{ information.value }}</p>
7273
</ion-label>
7374
</ion-item>
7475
</ion-list>
76+
<section>
77+
<ion-button expand="block" [routerLink]="['/information', {hash: (hash$ | async)}]">View All
78+
</ion-button>
79+
</section>
7580
</ion-card-content>
7681
</ion-card>
7782
</ion-slide>

src/app/pages/proof/proof.page.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { defer } from 'rxjs';
77
import { first, map, pluck, switchMap, switchMapTo } from 'rxjs/operators';
88
import { ConfirmAlert } from 'src/app/services/confirm-alert/confirm-alert.service';
99
import { CaptionRepository } from 'src/app/services/data/caption/caption-repository.service';
10+
import { Importance } from 'src/app/services/data/information/information';
1011
import { InformationRepository } from 'src/app/services/data/information/information-repository.service';
1112
import { ProofRepository } from 'src/app/services/data/proof/proof-repository.service';
1213
import { SignatureRepository } from 'src/app/services/data/signature/signature-repository.service';
@@ -27,6 +28,7 @@ export class ProofPage {
2728
switchMap(hash => this.proofRepository.getByHash$(hash)),
2829
isNonNullable()
2930
);
31+
3032
readonly rawBase64$ = this.proof$.pipe(switchMap(proof => this.proofRepository.getRawFile$(proof)));
3133
readonly hash$ = this.proof$.pipe(pluck('hash'));
3234
readonly mimeType$ = this.proof$.pipe(pluck('mimeType', 'type'));
@@ -38,16 +40,20 @@ export class ProofPage {
3840
return '';
3941
})
4042
);
41-
readonly providersWithInformationList$ = this.proof$.pipe(
43+
44+
readonly providersWithImportantInformation$ = this.proof$.pipe(
4245
switchMap(proof => this.informationRepository.getByProof$(proof)),
4346
map(informationList => {
4447
const providers = new Set(informationList.map(information => information.provider));
4548
return [...providers].map(provider => ({
4649
provider,
47-
informationList: informationList.filter(information => information.provider === provider)
50+
informationList: informationList.filter(
51+
information => information.provider === provider && information.importance === Importance.High
52+
)
4853
}));
4954
})
5055
);
56+
5157
readonly signatures$ = this.proof$.pipe(
5258
switchMap(proof => this.signatureRepository.getByProof$(proof))
5359
);

0 commit comments

Comments
 (0)