diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts
index 40a8e54d2..e62f5493c 100644
--- a/src/app/app-routing.module.ts
+++ b/src/app/app-routing.module.ts
@@ -14,6 +14,9 @@ const routes: Routes = [{
}, {
path: 'proof',
loadChildren: () => import('./pages/proof/proof.module').then(m => m.ProofPageModule)
+}, {
+ path: 'information',
+ loadChildren: () => import('./pages/information/information.module').then(m => m.InformationPageModule)
}];
@NgModule({
diff --git a/src/app/pages/information/information-routing.module.ts b/src/app/pages/information/information-routing.module.ts
new file mode 100644
index 000000000..dc82f9a3e
--- /dev/null
+++ b/src/app/pages/information/information-routing.module.ts
@@ -0,0 +1,14 @@
+import { NgModule } from '@angular/core';
+import { RouterModule, Routes } from '@angular/router';
+import { InformationPage } from './information.page';
+
+const routes: Routes = [{
+ path: '',
+ component: InformationPage
+}];
+
+@NgModule({
+ imports: [RouterModule.forChild(routes)],
+ exports: [RouterModule],
+})
+export class InformationPageRoutingModule { }
diff --git a/src/app/pages/information/information.module.ts b/src/app/pages/information/information.module.ts
new file mode 100644
index 000000000..c0b55be49
--- /dev/null
+++ b/src/app/pages/information/information.module.ts
@@ -0,0 +1,19 @@
+import { CommonModule } from '@angular/common';
+import { NgModule } from '@angular/core';
+import { FormsModule } from '@angular/forms';
+import { IonicModule } from '@ionic/angular';
+import { TranslocoModule } from '@ngneat/transloco';
+import { InformationPageRoutingModule } from './information-routing.module';
+import { InformationPage } from './information.page';
+
+@NgModule({
+ imports: [
+ CommonModule,
+ FormsModule,
+ IonicModule,
+ InformationPageRoutingModule,
+ TranslocoModule
+ ],
+ declarations: [InformationPage]
+})
+export class InformationPageModule { }
diff --git a/src/app/pages/information/information.page.html b/src/app/pages/information/information.page.html
new file mode 100644
index 000000000..8ddba8475
--- /dev/null
+++ b/src/app/pages/information/information.page.html
@@ -0,0 +1,69 @@
+
+
+
+
+
+
+
+ {{ t('informationDetails') }}
+
+
+
+
+
+
+
+ {{ t('location') }}
+
+
+
+
+
+ {{ information.name }}
+ {{ information.value }}
+
+
+
+
+
+
+
+
+
+
+
+ {{ t('other') }}
+
+
+
+
+
+ {{ information.name }}
+ {{ information.value }}
+
+
+
+
+
+
+
+
+
+
+
+ {{ t('device') }}
+
+
+
+
+
+ {{ information.name }}
+ {{ information.value }}
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/app/pages/information/information.page.scss b/src/app/pages/information/information.page.scss
new file mode 100644
index 000000000..410d97ad1
--- /dev/null
+++ b/src/app/pages/information/information.page.scss
@@ -0,0 +1,7 @@
+.slide-card {
+ width: 100%;
+}
+
+.multiline {
+ white-space: pre-wrap;
+}
diff --git a/src/app/pages/information/information.page.spec.ts b/src/app/pages/information/information.page.spec.ts
new file mode 100644
index 000000000..53322231a
--- /dev/null
+++ b/src/app/pages/information/information.page.spec.ts
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { RouterTestingModule } from '@angular/router/testing';
+import { IonicModule } from '@ionic/angular';
+import { getTranslocoModule } from 'src/app/transloco/transloco-root.module.spec';
+import { InformationPage } from './information.page';
+
+describe('InformationPage', () => {
+ let component: InformationPage;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [InformationPage],
+ imports: [IonicModule.forRoot(), RouterTestingModule, getTranslocoModule()]
+ }).compileComponents();
+
+ fixture = TestBed.createComponent(InformationPage);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ }));
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/app/pages/information/information.page.ts b/src/app/pages/information/information.page.ts
new file mode 100644
index 000000000..bab91ab3b
--- /dev/null
+++ b/src/app/pages/information/information.page.ts
@@ -0,0 +1,54 @@
+import { Component } from '@angular/core';
+import { ActivatedRoute } from '@angular/router';
+import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
+import { map, pluck, switchMap, switchMapTo } from 'rxjs/operators';
+import { InformationType } from 'src/app/services/data/information/information';
+import { InformationRepository } from 'src/app/services/data/information/information-repository.service';
+import { ProofRepository } from 'src/app/services/data/proof/proof-repository.service';
+import { isNonNullable } from 'src/app/utils/rx-operators';
+
+@UntilDestroy({ checkProperties: true })
+@Component({
+ selector: 'app-information',
+ templateUrl: './information.page.html',
+ styleUrls: ['./information.page.scss'],
+})
+export class InformationPage {
+
+ readonly proof$ = this.route.paramMap.pipe(
+ map(params => params.get('hash')),
+ isNonNullable(),
+ switchMap(hash => this.proofRepository.getByHash$(hash)),
+ isNonNullable()
+ );
+
+ readonly hash$ = this.proof$.pipe(pluck('hash'));
+
+ readonly locationInformation$ = this.proof$.pipe(
+ switchMap(proof => this.informationRepository.getByProof$(proof)),
+ map(informationList => informationList.filter(information => information.type === InformationType.Location))
+ );
+
+ readonly otherInformation$ = this.proof$.pipe(
+ switchMap(proof => this.informationRepository.getByProof$(proof)),
+ map(informationList => informationList.filter(information => information.type === InformationType.Other))
+ );
+
+ readonly deviceInformation$ = this.proof$.pipe(
+ switchMap(proof => this.informationRepository.getByProof$(proof)),
+ map(informationList => informationList.filter(information => information.type === InformationType.Device))
+ );
+
+ constructor(
+ private readonly route: ActivatedRoute,
+ private readonly proofRepository: ProofRepository,
+ private readonly informationRepository: InformationRepository,
+ ) { }
+
+ ionViewWillEnter() {
+ this.proofRepository.refresh$().pipe(
+ switchMapTo(this.informationRepository.refresh$()),
+ untilDestroyed(this)
+ ).subscribe();
+ }
+}
diff --git a/src/app/pages/proof/proof.page.html b/src/app/pages/proof/proof.page.html
index 5e31f6333..22410603f 100644
--- a/src/app/pages/proof/proof.page.html
+++ b/src/app/pages/proof/proof.page.html
@@ -1,7 +1,7 @@
-
+
@@ -58,20 +58,25 @@ {{ t('information') }}
-
-
+
+
{{ providerWithInformationList.provider }}
-
-
+
+
{{ information.name }}
{{ information.value }}
+
diff --git a/src/app/pages/proof/proof.page.ts b/src/app/pages/proof/proof.page.ts
index 160ab8b63..aaf868bfe 100644
--- a/src/app/pages/proof/proof.page.ts
+++ b/src/app/pages/proof/proof.page.ts
@@ -7,6 +7,7 @@ import { defer } from 'rxjs';
import { first, map, pluck, switchMap, switchMapTo } from 'rxjs/operators';
import { ConfirmAlert } from 'src/app/services/confirm-alert/confirm-alert.service';
import { CaptionRepository } from 'src/app/services/data/caption/caption-repository.service';
+import { Importance } from 'src/app/services/data/information/information';
import { InformationRepository } from 'src/app/services/data/information/information-repository.service';
import { ProofRepository } from 'src/app/services/data/proof/proof-repository.service';
import { SignatureRepository } from 'src/app/services/data/signature/signature-repository.service';
@@ -27,6 +28,7 @@ export class ProofPage {
switchMap(hash => this.proofRepository.getByHash$(hash)),
isNonNullable()
);
+
readonly rawBase64$ = this.proof$.pipe(switchMap(proof => this.proofRepository.getRawFile$(proof)));
readonly hash$ = this.proof$.pipe(pluck('hash'));
readonly mimeType$ = this.proof$.pipe(pluck('mimeType', 'type'));
@@ -38,16 +40,20 @@ export class ProofPage {
return '';
})
);
- readonly providersWithInformationList$ = this.proof$.pipe(
+
+ readonly providersWithImportantInformation$ = this.proof$.pipe(
switchMap(proof => this.informationRepository.getByProof$(proof)),
map(informationList => {
const providers = new Set(informationList.map(information => information.provider));
return [...providers].map(provider => ({
provider,
- informationList: informationList.filter(information => information.provider === provider)
+ informationList: informationList.filter(
+ information => information.provider === provider && information.importance === Importance.High
+ )
}));
})
);
+
readonly signatures$ = this.proof$.pipe(
switchMap(proof => this.signatureRepository.getByProof$(proof))
);
diff --git a/src/app/services/collector/information/capacitor-provider/capacitor-provider.ts b/src/app/services/collector/information/capacitor-provider/capacitor-provider.ts
index 88ca9d5ef..2005d8726 100644
--- a/src/app/services/collector/information/capacitor-provider/capacitor-provider.ts
+++ b/src/app/services/collector/information/capacitor-provider/capacitor-provider.ts
@@ -2,7 +2,7 @@ import { Plugins } from '@capacitor/core';
import { TranslocoService } from '@ngneat/transloco';
import { defer, Observable, of, zip } from 'rxjs';
import { first, map, switchMap } from 'rxjs/operators';
-import { Information } from 'src/app/services/data/information/information';
+import { Importance, Information, InformationType } from 'src/app/services/data/information/information';
import { InformationRepository } from 'src/app/services/data/information/information-repository.service';
import { Proof } from 'src/app/services/data/proof/proof';
import { PreferenceManager } from 'src/app/utils/preferences/preference-manager';
@@ -64,68 +64,94 @@ export class CapacitorProvider extends InformationProvider {
informationList.push({
proofHash: proof.hash,
provider: this.name,
- name: this.translocoService.translate('deviceName'),
- value: String(deviceInfo.name)
+ name: this.translocoService.translate('uuid'),
+ value: String(deviceInfo.uuid),
+ importance: Importance.High,
+ type: InformationType.Other
}, {
proofHash: proof.hash,
provider: this.name,
- name: this.translocoService.translate('deviceModel'),
- value: String(deviceInfo.model)
+ name: this.translocoService.translate('deviceName'),
+ value: String(deviceInfo.name),
+ importance: Importance.Low,
+ type: InformationType.Device
}, {
proofHash: proof.hash,
provider: this.name,
- name: this.translocoService.translate('devicePlatform'),
- value: String(deviceInfo.platform)
+ name: this.translocoService.translate('deviceModel'),
+ value: String(deviceInfo.model),
+ importance: Importance.Low,
+ type: InformationType.Device
}, {
proofHash: proof.hash,
provider: this.name,
- name: this.translocoService.translate('uuid'),
- value: String(deviceInfo.uuid)
+ name: this.translocoService.translate('devicePlatform'),
+ value: String(deviceInfo.platform),
+ importance: Importance.Low,
+ type: InformationType.Device
}, {
proofHash: proof.hash,
provider: this.name,
name: this.translocoService.translate('appVersion'),
- value: String(deviceInfo.appVersion)
+ value: String(deviceInfo.appVersion),
+ importance: Importance.Low,
+ type: InformationType.Device
}, {
proofHash: proof.hash,
provider: this.name,
name: this.translocoService.translate('appVersionCode'),
- value: String(deviceInfo.appBuild)
+ value: String(deviceInfo.appBuild),
+ importance: Importance.Low,
+ type: InformationType.Device
}, {
proofHash: proof.hash,
provider: this.name,
name: this.translocoService.translate('operatingSystem'),
- value: String(deviceInfo.operatingSystem)
+ value: String(deviceInfo.operatingSystem),
+ importance: Importance.Low,
+ type: InformationType.Device
}, {
proofHash: proof.hash,
provider: this.name,
name: this.translocoService.translate('osVersion'),
- value: String(deviceInfo.osVersion)
+ value: String(deviceInfo.osVersion),
+ importance: Importance.Low,
+ type: InformationType.Device
}, {
proofHash: proof.hash,
provider: this.name,
name: this.translocoService.translate('deviceManufacturer'),
- value: String(deviceInfo.manufacturer)
+ value: String(deviceInfo.manufacturer),
+ importance: Importance.Low,
+ type: InformationType.Device
}, {
proofHash: proof.hash,
provider: this.name,
name: this.translocoService.translate('runningOnVm'),
- value: String(deviceInfo.isVirtual)
+ value: String(deviceInfo.isVirtual),
+ importance: Importance.Low,
+ type: InformationType.Device
}, {
proofHash: proof.hash,
provider: this.name,
name: this.translocoService.translate('usedMemory'),
- value: String(deviceInfo.memUsed)
+ value: String(deviceInfo.memUsed),
+ importance: Importance.Low,
+ type: InformationType.Device
}, {
proofHash: proof.hash,
provider: this.name,
name: this.translocoService.translate('freeDiskSpace'),
- value: String(deviceInfo.diskFree)
+ value: String(deviceInfo.diskFree),
+ importance: Importance.Low,
+ type: InformationType.Device
}, {
proofHash: proof.hash,
provider: this.name,
name: this.translocoService.translate('totalDiskSpace'),
- value: String(deviceInfo.diskTotal)
+ value: String(deviceInfo.diskTotal),
+ importance: Importance.Low,
+ type: InformationType.Device
});
}
if (batteryInfo !== undefined) {
@@ -133,12 +159,16 @@ export class CapacitorProvider extends InformationProvider {
proofHash: proof.hash,
provider: this.name,
name: this.translocoService.translate('batteryLevel'),
- value: String(batteryInfo.batteryLevel)
+ value: String(batteryInfo.batteryLevel),
+ importance: Importance.Low,
+ type: InformationType.Device
}, {
proofHash: proof.hash,
provider: this.name,
name: this.translocoService.translate('batteryCharging'),
- value: String(batteryInfo.isCharging)
+ value: String(batteryInfo.isCharging),
+ importance: Importance.Low,
+ type: InformationType.Device
});
}
if (languageCode !== undefined) {
@@ -146,7 +176,9 @@ export class CapacitorProvider extends InformationProvider {
proofHash: proof.hash,
provider: this.name,
name: this.translocoService.translate('deviceLanguageCode'),
- value: String(languageCode.value)
+ value: String(languageCode.value),
+ importance: Importance.Low,
+ type: InformationType.Device
});
}
if (geolocationPosition !== undefined) {
@@ -154,7 +186,9 @@ export class CapacitorProvider extends InformationProvider {
proofHash: proof.hash,
provider: this.name,
name: this.translocoService.translate('location'),
- value: `(${geolocationPosition.coords.latitude}, ${geolocationPosition.coords.longitude})`
+ value: `(${geolocationPosition.coords.latitude}, ${geolocationPosition.coords.longitude})`,
+ importance: Importance.High,
+ type: InformationType.Location
});
}
return informationList;
diff --git a/src/app/services/data/information/information.ts b/src/app/services/data/information/information.ts
index 8cd23f736..99579c40e 100644
--- a/src/app/services/data/information/information.ts
+++ b/src/app/services/data/information/information.ts
@@ -1,6 +1,19 @@
+export const enum Importance {
+ Low = 'low',
+ High = 'high'
+}
+
+export const enum InformationType {
+ Device = 'device',
+ Location = 'location',
+ Other = 'other'
+}
+
export interface Information {
readonly proofHash: string;
readonly provider: string;
readonly name: string;
readonly value: string;
+ readonly importance: Importance;
+ readonly type: InformationType;
}
diff --git a/src/assets/i18n/en-us.json b/src/assets/i18n/en-us.json
index 0745823ce..13e95a7dd 100644
--- a/src/assets/i18n/en-us.json
+++ b/src/assets/i18n/en-us.json
@@ -2,8 +2,10 @@
"capture": "Capture",
"settings": "Settings",
"proofDetails": "Proof Details",
+ "informationDetails": "Information Details",
"caption": "Caption",
"hash": "Hash",
+ "other": "Other",
"mimeType": "MIME Type",
"timestamp": "Timestamp",
"information": "Information",
@@ -48,6 +50,9 @@
"collectDeviceInfo": "Collect Device Info",
"collectLocationInfo": "Collect Location Info",
"unknownError": "Unknown Error",
+ "low": "Low",
+ "high": "High",
+ "device": "Device",
"message": {
"areYouSure": "This action cannot be undone.",
"publishingProof": "Publishing proof {{hash}} to {{publisherName}}.",