1
1
import { Inject , Injectable } from '@angular/core' ;
2
- import { defer , fromEvent , Observable , throwError } from 'rxjs' ;
2
+ import { SERVICE_WORKER } from '@ng-web-apis/common' ;
3
+ import {
4
+ filter ,
5
+ from ,
6
+ fromEvent ,
7
+ map ,
8
+ NEVER ,
9
+ Observable ,
10
+ shareReplay ,
11
+ switchMap ,
12
+ throwError ,
13
+ } from 'rxjs' ;
3
14
import { takeUntil } from 'rxjs/operators' ;
4
15
16
+ import { NOTIFICATION_SW_CLICKS } from '../tokens/notification-clicks' ;
17
+ import { NOTIFICATION_SW_CLOSES } from '../tokens/notification-closes' ;
18
+ import { NOTIFICATION_FACTORY } from '../tokens/notification-factory' ;
5
19
import { NOTIFICATION_SUPPORT } from '../tokens/support' ;
20
+ import { InjectionTokenType } from '../types/injection-token-type' ;
6
21
7
22
const NOT_SUPPORTED_ERROR$ = throwError (
8
23
( ) => new Error ( 'Notification API is not supported in your browser' ) ,
@@ -12,7 +27,26 @@ const NOT_SUPPORTED_ERROR$ = throwError(
12
27
providedIn : 'root' ,
13
28
} )
14
29
export class NotificationService {
15
- constructor ( @Inject ( NOTIFICATION_SUPPORT ) private readonly support : boolean ) { }
30
+ private readonly swRegistration$ = from ( this . sw . getRegistration ( ) ) . pipe (
31
+ shareReplay ( 1 ) ,
32
+ ) ;
33
+
34
+ constructor (
35
+ @Inject ( NOTIFICATION_SUPPORT ) private readonly support : boolean ,
36
+ @Inject ( NOTIFICATION_FACTORY )
37
+ private readonly createNotification : InjectionTokenType <
38
+ typeof NOTIFICATION_FACTORY
39
+ > ,
40
+ @Inject ( NOTIFICATION_SW_CLICKS )
41
+ private readonly notificationSwClicks$ : InjectionTokenType <
42
+ typeof NOTIFICATION_SW_CLICKS
43
+ > ,
44
+ @Inject ( NOTIFICATION_SW_CLOSES )
45
+ private readonly notificationSwCloses$ : InjectionTokenType <
46
+ typeof NOTIFICATION_SW_CLOSES
47
+ > ,
48
+ @Inject ( SERVICE_WORKER ) private readonly sw : ServiceWorkerContainer ,
49
+ ) { }
16
50
17
51
requestPermission ( ) : Observable < NotificationPermission > {
18
52
if ( ! this . support ) {
@@ -36,15 +70,48 @@ export class NotificationService {
36
70
return NOT_SUPPORTED_ERROR$ ;
37
71
}
38
72
39
- return defer ( ( ) => {
40
- const notification = new Notification ( title , options ) ;
41
- const close$ = fromEvent ( notification , 'close' ) ;
73
+ return from ( this . createNotification ( title , options ) ) . pipe (
74
+ switchMap ( notification => {
75
+ const close$ = this . fromEvent ( notification , 'close' ) ;
42
76
43
- return new Observable < Notification > ( subscriber => {
44
- subscriber . next ( notification ) ;
77
+ return new Observable < Notification > ( subscriber => {
78
+ subscriber . next ( notification ) ;
45
79
46
- return ( ) => notification . close ( ) ;
47
- } ) . pipe ( takeUntil ( close$ ) ) ;
48
- } ) ;
80
+ return ( ) => notification . close ( ) ;
81
+ } ) . pipe ( takeUntil ( close$ ) ) ;
82
+ } ) ,
83
+ ) ;
84
+ }
85
+
86
+ fromEvent < E extends keyof NotificationEventMap > (
87
+ targetNotification : Notification ,
88
+ eventName : E ,
89
+ ) : Observable < { action : string } | void > {
90
+ const mapToVoid = map ( ( ) => undefined ) ;
91
+
92
+ return this . swRegistration$ . pipe (
93
+ switchMap ( swRegistration => {
94
+ if ( ! swRegistration ) {
95
+ return fromEvent ( targetNotification , eventName ) . pipe ( mapToVoid ) ;
96
+ }
97
+
98
+ const isTargetNotification = ( notification : { timestamp ?: number } ) =>
99
+ notification . timestamp === targetNotification . timestamp ;
100
+
101
+ switch ( eventName ) {
102
+ case 'click' :
103
+ return this . notificationSwClicks$ . pipe (
104
+ filter ( x => isTargetNotification ( x . notification ) ) ,
105
+ ) ;
106
+ case 'close' :
107
+ return this . notificationSwCloses$ . pipe (
108
+ filter ( isTargetNotification ) ,
109
+ mapToVoid ,
110
+ ) ;
111
+ default :
112
+ return NEVER ;
113
+ }
114
+ } ) ,
115
+ ) ;
49
116
}
50
117
}
0 commit comments