11import  { 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' ; 
314import  { takeUntil }  from  'rxjs/operators' ; 
415
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' ; 
519import  { NOTIFICATION_SUPPORT }  from  '../tokens/support' ; 
20+ import  { InjectionTokenType }  from  '../types/injection-token-type' ; 
621
722const  NOT_SUPPORTED_ERROR$  =  throwError ( 
823    ( )  =>  new  Error ( 'Notification API is not supported in your browser' ) , 
@@ -12,7 +27,26 @@ const NOT_SUPPORTED_ERROR$ = throwError(
1227    providedIn : 'root' , 
1328} ) 
1429export  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+     )  { } 
1650
1751    requestPermission ( ) : Observable < NotificationPermission >  { 
1852        if  ( ! this . support )  { 
@@ -36,15 +70,48 @@ export class NotificationService {
3670            return  NOT_SUPPORTED_ERROR$ ; 
3771        } 
3872
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' ) ; 
4276
43-             return  new  Observable < Notification > ( subscriber  =>  { 
44-                 subscriber . next ( notification ) ; 
77+                  return  new  Observable < Notification > ( subscriber  =>  { 
78+                      subscriber . next ( notification ) ; 
4579
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+         ) ; 
49116    } 
50117} 
0 commit comments