Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature receive postcapture notification #310

Merged
merged 30 commits into from
Dec 10, 2020
Merged
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
6ddbf45
Remove unused rx-operators.
seanwu1105 Dec 7, 2020
8c56b06
Implement DiaBackendContactRepository.
seanwu1105 Dec 7, 2020
8ae3a38
Show contacts on contact-selection-dialog.
seanwu1105 Dec 7, 2020
11e908f
Show progress spinner when fetching contacts with empty cache.
seanwu1105 Dec 7, 2020
a021f40
Add argument for comparator to Table.insert method.
seanwu1105 Dec 8, 2020
34c1f4e
Implement OnConflictStrategy.REPLACE for Table.insert.
seanwu1105 Dec 8, 2020
afff62b
Implement comparator for Table.delete method.
seanwu1105 Dec 8, 2020
d79fb9b
Update DiaBackendContact endpoint APIs.
seanwu1105 Dec 8, 2020
bdfdc2d
Merge branch 'develop' into feature-contacts
seanwu1105 Dec 8, 2020
deb9a13
Refactor PushNotificationService.
seanwu1105 Dec 8, 2020
b14b608
Remove unused InviteContactResponse interface.
seanwu1105 Dec 8, 2020
a08e314
Replace test account with mock account.
seanwu1105 Dec 8, 2020
02054ff
Show notification when receving PostCapture.
seanwu1105 Dec 8, 2020
eabdfb9
WIP: Implement polling to get expired assets.
seanwu1105 Dec 8, 2020
ee13759
Merge branch 'feature-contacts' into feature-receive-postcapture-noti…
seanwu1105 Dec 8, 2020
804f8e5
WORKAROUND: Implement polling to get expired assets.
seanwu1105 Dec 8, 2020
008d71e
Show notification on a PostCapture expired.
seanwu1105 Dec 8, 2020
218b1ec
Show only empty badge on inbox icon.
seanwu1105 Dec 8, 2020
cf5fa69
Merge branch 'develop' into feature-receive-postcapture-notification
seanwu1105 Dec 8, 2020
91d6bd8
Rename activity to transaction.
seanwu1105 Dec 9, 2020
9e3210c
WIP
seanwu1105 Dec 9, 2020
dd3a21f
Refactor DiaBackendTransactionRepository with related pages.
seanwu1105 Dec 9, 2020
728f60f
Show spinner on transaction page when transaction cache is empty and …
seanwu1105 Dec 9, 2020
4e1cd50
Show spinner when inbox is fetching without local cache.
seanwu1105 Dec 9, 2020
f2988a9
Remove polling for inbox count.
seanwu1105 Dec 9, 2020
cc13c74
Merge branch 'feature-receive-postcapture-notification' into refactor…
seanwu1105 Dec 9, 2020
9c8f65e
Remove all polling methods in home page component with repository pat…
seanwu1105 Dec 9, 2020
7918762
Merge branch 'develop' into feature-receive-postcapture-notification
seanwu1105 Dec 10, 2020
5d983e2
Merge branch 'develop' into feature-receive-postcapture-notification
seanwu1105 Dec 10, 2020
aaeb1c7
Merge branch 'develop' into feature-receive-postcapture-notification
seanwu1105 Dec 10, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,11 @@ import { CollectorService } from './services/collector/collector.service';
import { CapacitorFactsProvider } from './services/collector/facts/capacitor-facts-provider/capacitor-facts-provider.service';
import { WebCryptoApiSignatureProvider } from './services/collector/signature/web-crypto-api-signature-provider/web-crypto-api-signature-provider.service';
import { DiaBackendAssetRepository } from './services/dia-backend/asset/dia-backend-asset-repository.service';
import { DiaBackendAuthService } from './services/dia-backend/auth/dia-backend-auth.service';
import { DiaBackendNotificationService } from './services/dia-backend/notification/dia-backend-notification.service';
import { LanguageService } from './services/language/language.service';
import { NotificationService } from './services/notification/notification.service';
import { PushNotificationService } from './services/push-notification/push-notification.service';
import { restoreKilledCapture } from './utils/camera';

const { SplashScreen } = Plugins;
Expand All @@ -32,16 +35,27 @@ export class AppComponent {
private readonly webCryptoApiSignatureProvider: WebCryptoApiSignatureProvider,
private readonly diaBackendAssetRepository: DiaBackendAssetRepository,
notificationService: NotificationService,
langaugeService: LanguageService
pushNotificationService: PushNotificationService,
langaugeService: LanguageService,
diaBackendAuthService: DiaBackendAuthService,
diaBackendNotificationService: DiaBackendNotificationService
) {
notificationService.requestPermission();
pushNotificationService.register();
langaugeService.initialize();
diaBackendAuthService.initialize$().pipe(untilDestroyed(this)).subscribe();
diaBackendNotificationService
.initialize$()
.pipe(untilDestroyed(this))
.subscribe();
this.restoreAppStatus();
this.initializeApp();
this.initializeCollector();
this.registerIcon();
}

// TODO: Error if user logout during app killed. Use BehaviorSubject instead.
// Extract this to a standalone CameraService.
restoreAppStatus() {
return defer(restoreKilledCapture)
.pipe(
Expand Down
10 changes: 0 additions & 10 deletions src/app/pages/home/activity/activity.module.ts

This file was deleted.

24 changes: 0 additions & 24 deletions src/app/pages/home/activity/activity.page.html

This file was deleted.

61 changes: 0 additions & 61 deletions src/app/pages/home/activity/activity.page.ts

This file was deleted.

This file was deleted.

2 changes: 1 addition & 1 deletion src/app/pages/home/asset/asset.page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { ConfirmAlert } from '../../../services/confirm-alert/confirm-alert.serv
import { DiaBackendAssetRepository } from '../../../services/dia-backend/asset/dia-backend-asset-repository.service';
import { getOldProof } from '../../../services/repositories/proof/old-proof-adapter';
import { ProofRepository } from '../../../services/repositories/proof/proof-repository.service';
import { isNonNullable } from '../../../utils/rx-operators';
import { isNonNullable } from '../../../utils/rx-operators/rx-operators';
import { ContactSelectionDialogComponent } from './contact-selection-dialog/contact-selection-dialog.component';
import {
Option,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Component } from '@angular/core';
import { MatDialog, MatDialogRef } from '@angular/material/dialog';
import { DiaBackendContactRepository } from '../../../../services/dia-backend/contact/dia-backend-contact-repository.service';
import { isNonNullable } from '../../../../utils/rx-operators';
import { isNonNullable } from '../../../../utils/rx-operators/rx-operators';
import { FriendInvitationDialogComponent } from './friend-invitation-dialog/friend-invitation-dialog.component';

@Component({
Expand Down
2 changes: 1 addition & 1 deletion src/app/pages/home/asset/information/information.page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
getOldSignatures,
} from '../../../../services/repositories/proof/old-proof-adapter';
import { ProofRepository } from '../../../../services/repositories/proof/proof-repository.service';
import { isNonNullable } from '../../../../utils/rx-operators';
import { isNonNullable } from '../../../../utils/rx-operators/rx-operators';

@UntilDestroy({ checkProperties: true })
@Component({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { DiaBackendAssetRepository } from '../../../../services/dia-backend/asse
import { DiaBackendTransactionRepository } from '../../../../services/dia-backend/transaction/dia-backend-transaction-repository.service';
import { getOldProof } from '../../../../services/repositories/proof/old-proof-adapter';
import { ProofRepository } from '../../../../services/repositories/proof/proof-repository.service';
import { isNonNullable } from '../../../../utils/rx-operators';
import { isNonNullable } from '../../../../utils/rx-operators/rx-operators';

@UntilDestroy({ checkProperties: true })
@Component({
Expand Down
6 changes: 4 additions & 2 deletions src/app/pages/home/home-routing.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@ const routes: Routes = [
import('./inbox/inbox.module').then(m => m.InboxPageModule),
},
{
path: 'activity',
path: 'transaction',
loadChildren: () =>
import('./activity/activity.module').then(m => m.ActivityPageModule),
import('./transaction/transaction.module').then(
m => m.TransactionPageModule
),
},
];

Expand Down
5 changes: 3 additions & 2 deletions src/app/pages/home/home.page.html
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,14 @@
<mat-icon>menu</mat-icon>
</button>
<span class="toolbar-spacer"></span>
<button routerLink="activity" mat-icon-button>
<button routerLink="transaction" mat-icon-button>
<mat-icon>history</mat-icon>
</button>
<button routerLink="inbox" mat-icon-button>
<mat-icon
[matBadge]="inboxCount$ | async"
matBadge="&#8288;"
[matBadgeHidden]="!(inboxCount$ | async)"
matBadgeSize="small"
matBadgeColor="warn"
>
all_inbox</mat-icon
Expand Down
6 changes: 2 additions & 4 deletions src/app/pages/home/home.page.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@ describe('HomePage', () => {
fixture.detectChanges();
}));

// TODO: Enable this after removing the polling WORKAROUND
// it('should create', () => {
// expect(component).toBeTruthy();
// });
// TODO: Enable this test after we remove the ugly WORKAROUND in ngOnInit().
// it('should create', () => expect(component).toBeTruthy());
});
116 changes: 72 additions & 44 deletions src/app/pages/home/home.page.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
import { formatDate } from '@angular/common';
import { HttpClient } from '@angular/common/http';
import { Component, OnInit } from '@angular/core';
import { MatTabChangeEvent } from '@angular/material/tabs';
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
import { groupBy } from 'lodash';
import { combineLatest, defer, forkJoin, interval, of, zip } from 'rxjs';
import { concatMap, concatMapTo, first, map, pluck } from 'rxjs/operators';
import { combineLatest, defer, forkJoin, of, zip } from 'rxjs';
import { concatMap, first, map } from 'rxjs/operators';
import { CollectorService } from '../../services/collector/collector.service';
import { OnConflictStrategy } from '../../services/database/table/table';
import { DiaBackendAssetRepository } from '../../services/dia-backend/asset/dia-backend-asset-repository.service';
import { DiaBackendAuthService } from '../../services/dia-backend/auth/dia-backend-auth.service';
import { DiaBackendTransactionRepository } from '../../services/dia-backend/transaction/dia-backend-transaction-repository.service';
import { IgnoredTransactionRepository } from '../../services/dia-backend/transaction/ignored-transaction-repository.service';
import { PushNotificationService } from '../../services/push-notification/push-notification.service';
import { getOldProof } from '../../services/repositories/proof/old-proof-adapter';
import { ImageStore } from '../../services/image-store/image-store.service';
import {
getOldProof,
getProof,
} from '../../services/repositories/proof/old-proof-adapter';
import { Proof } from '../../services/repositories/proof/proof';
import { ProofRepository } from '../../services/repositories/proof/proof-repository.service';
import { capture } from '../../utils/camera';
Expand All @@ -37,9 +41,9 @@ export class HomePage implements OnInit {
postCaptures$ = this.getPostCaptures$();
readonly username$ = this.diaBackendAuthService.getUsername$();
captureButtonShow = true;
inboxCount$ = this.pollingInbox$().pipe(
map(transactions => transactions.length)
);
inboxCount$ = this.diaBackendTransactionRepository
.getInbox$()
.pipe(map(transactions => transactions.length));
currentUploadingProofHash = '';

constructor(
Expand All @@ -48,12 +52,65 @@ export class HomePage implements OnInit {
private readonly diaBackendAuthService: DiaBackendAuthService,
private readonly diaBackendAssetRepository: DiaBackendAssetRepository,
private readonly diaBackendTransactionRepository: DiaBackendTransactionRepository,
private readonly pushNotificationService: PushNotificationService,
private readonly ignoredTransactionRepository: IgnoredTransactionRepository
private readonly imageStore: ImageStore,
private readonly httpClient: HttpClient
) {}

ngOnInit() {
this.pushNotificationService.configure();
/**
* TODO: Remove this ugly WORKAROUND by using repository pattern to cache the expired assets and proofs.
* TODO: Move this functionality to DiaBackendAssetRepository.initialize$() method.
*/
this.diaBackendTransactionRepository
.getAll$()
.pipe(
concatMap(transactions =>
forkJoin([
of(transactions),
defer(() => this.diaBackendAuthService.getEmail()),
])
),
map(([transactions, email]) =>
transactions.filter(t => t.expired && t.sender === email)
),
concatMap(expiredTransactions =>
forkJoin(
expiredTransactions.map(t =>
this.diaBackendAssetRepository.getById$(t.asset.id)
)
)
),
concatMap(expiredAssets =>
forkJoin([
of(expiredAssets),
defer(() =>
Promise.all(
expiredAssets.map(async a => {
return this.proofRepository.add(
await getProof(
this.imageStore,
await this.httpClient
.get(a.asset_file, { responseType: 'blob' })
.toPromise(),
a.information,
a.signature
),
OnConflictStrategy.REPLACE
);
})
)
),
])
),
concatMap(([expiredAssets]) =>
this.diaBackendAssetRepository.addAssetDirectly(
expiredAssets,
OnConflictStrategy.REPLACE
)
),
untilDestroyed(this)
)
.subscribe();
}

private getCaptures$() {
Expand Down Expand Up @@ -83,13 +140,14 @@ export class HomePage implements OnInit {
);
}

// TODO: Clean up this ugly WORKAROUND with repository pattern.
private getPostCaptures$() {
return zip(
this.diaBackendTransactionRepository.getAll$(),
this.diaBackendTransactionRepository.getAll$().pipe(first()),
this.diaBackendAuthService.getEmail()
).pipe(
map(([transactionListResponse, email]) =>
transactionListResponse.results.filter(
map(([transactions, email]) =>
transactions.filter(
transaction =>
transaction.sender !== email &&
!transaction.expired &&
Expand Down Expand Up @@ -150,34 +208,4 @@ export class HomePage implements OnInit {
this.postCaptures$ = this.getPostCaptures$();
}
}

/**
* TODO: Use repository pattern to cache the inbox data.
*/
private pollingInbox$() {
// tslint:disable-next-line: no-magic-numbers
return interval(10000).pipe(
concatMapTo(this.diaBackendTransactionRepository.getAll$()),
pluck('results'),
concatMap(postCaptures =>
zip(of(postCaptures), this.diaBackendAuthService.getEmail())
),
map(([postCaptures, email]) =>
postCaptures.filter(
postCapture =>
postCapture.receiver_email === email &&
!postCapture.fulfilled_at &&
!postCapture.expired
)
),
concatMap(postCaptures =>
zip(of(postCaptures), this.ignoredTransactionRepository.getAll$())
),
map(([postCaptures, ignoredTransactions]) =>
postCaptures.filter(
postcapture => !ignoredTransactions.includes(postcapture.id)
)
)
);
}
}
Loading