Correctly handle standalone (PWA) mode changes
- Also handle notification permission changes - Remove web push schedule worker since this complicates things and doesn’t do _that_ much. We have the reminder notification if the user truly doesn’t reload ntfy in more than a week.
This commit is contained in:
		
							parent
							
								
									532fd3c560
								
							
						
					
					
						commit
						a8d3297c4e
					
				
					 6 changed files with 91 additions and 90 deletions
				
			
		|  | @ -15,7 +15,7 @@ import userManager from "../app/UserManager"; | |||
| import { expandUrl } from "../app/utils"; | ||||
| import ErrorBoundary from "./ErrorBoundary"; | ||||
| import routes from "./routes"; | ||||
| import { useAccountListener, useBackgroundProcesses, useConnectionListeners } from "./hooks"; | ||||
| import { useAccountListener, useBackgroundProcesses, useConnectionListeners, useWebPushTopics } from "./hooks"; | ||||
| import PublishDialog from "./PublishDialog"; | ||||
| import Messaging from "./Messaging"; | ||||
| import Login from "./Login"; | ||||
|  | @ -68,7 +68,7 @@ const Layout = () => { | |||
|   const [sendDialogOpenMode, setSendDialogOpenMode] = useState(""); | ||||
|   const users = useLiveQuery(() => userManager.all()); | ||||
|   const subscriptions = useLiveQuery(() => subscriptionManager.all()); | ||||
|   const webPushTopics = useLiveQuery(() => subscriptionManager.webPushTopics()); | ||||
|   const webPushTopics = useWebPushTopics(); | ||||
|   const subscriptionsWithoutInternal = subscriptions?.filter((s) => !s.internal); | ||||
|   const newNotificationsCount = subscriptionsWithoutInternal?.reduce((prev, cur) => prev + cur.new, 0) || 0; | ||||
|   const [selected] = (subscriptionsWithoutInternal || []).filter( | ||||
|  |  | |||
|  | @ -1,7 +1,8 @@ | |||
| import { useParams } from "react-router-dom"; | ||||
| import { useEffect, useMemo, useState } from "react"; | ||||
| import { useLiveQuery } from "dexie-react-hooks"; | ||||
| import subscriptionManager from "../app/SubscriptionManager"; | ||||
| import { disallowedTopic, expandSecureUrl, topicUrl } from "../app/utils"; | ||||
| import { disallowedTopic, expandSecureUrl, isLaunchedPWA, topicUrl } from "../app/utils"; | ||||
| import routes from "./routes"; | ||||
| import connectionManager from "../app/ConnectionManager"; | ||||
| import poller from "../app/Poller"; | ||||
|  | @ -9,7 +10,8 @@ import pruner from "../app/Pruner"; | |||
| import session from "../app/Session"; | ||||
| import accountApi from "../app/AccountApi"; | ||||
| import { UnauthorizedError } from "../app/errors"; | ||||
| import { webPush, useWebPushTopicListener } from "../app/WebPush"; | ||||
| import useWebPushListener from "../app/WebPush"; | ||||
| import notifier from "../app/Notifier"; | ||||
| 
 | ||||
| /** | ||||
|  * Wire connectionManager and subscriptionManager so that subscriptions are updated when the connection | ||||
|  | @ -133,6 +135,54 @@ export const useAutoSubscribe = (subscriptions, selected) => { | |||
|   }, [params, subscriptions, selected, hasRun]); | ||||
| }; | ||||
| 
 | ||||
| export const useWebPushTopics = () => { | ||||
|   const matchMedia = window.matchMedia("(display-mode: standalone)"); | ||||
| 
 | ||||
|   const [isStandalone, setIsStandalone] = useState(isLaunchedPWA()); | ||||
|   const [pushPossible, setPushPossible] = useState(notifier.pushPossible()); | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     const handler = (evt) => { | ||||
|       console.log(`[useWebPushTopics] App is now running ${evt.matches ? "standalone" : "in the browser"}`); | ||||
|       setIsStandalone(evt.matches); | ||||
|     }; | ||||
| 
 | ||||
|     matchMedia.addEventListener("change", handler); | ||||
| 
 | ||||
|     return () => { | ||||
|       matchMedia.removeEventListener("change", handler); | ||||
|     }; | ||||
|   }); | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     const handler = () => { | ||||
|       const newPushPossible = notifier.pushPossible(); | ||||
|       console.log(`[useWebPushTopics] Notification Permission changed`, { pushPossible: newPushPossible }); | ||||
|       setPushPossible(newPushPossible); | ||||
|     }; | ||||
| 
 | ||||
|     if ("permissions" in navigator) { | ||||
|       navigator.permissions.query({ name: "notifications" }).then((permission) => { | ||||
|         permission.addEventListener("change", handler); | ||||
| 
 | ||||
|         return () => { | ||||
|           permission.removeEventListener("change", handler); | ||||
|         }; | ||||
|       }); | ||||
|     } | ||||
|   }); | ||||
| 
 | ||||
|   const topics = useLiveQuery( | ||||
|     async () => subscriptionManager.webPushTopics(isStandalone, pushPossible), | ||||
|     // invalidate (reload) query when these values change
 | ||||
|     [isStandalone, pushPossible] | ||||
|   ); | ||||
| 
 | ||||
|   useWebPushListener(topics); | ||||
| 
 | ||||
|   return topics; | ||||
| }; | ||||
| 
 | ||||
| /** | ||||
|  * Start the poller and the pruner. This is done in a side effect as opposed to just in Pruner.js | ||||
|  * and Poller.js, because side effect imports are not a thing in JS, and "Optimize imports" cleans | ||||
|  | @ -143,19 +193,15 @@ const startWorkers = () => { | |||
|   poller.startWorker(); | ||||
|   pruner.startWorker(); | ||||
|   accountApi.startWorker(); | ||||
|   webPush.startWorker(); | ||||
| }; | ||||
| 
 | ||||
| const stopWorkers = () => { | ||||
|   poller.stopWorker(); | ||||
|   pruner.stopWorker(); | ||||
|   accountApi.stopWorker(); | ||||
|   webPush.stopWorker(); | ||||
| }; | ||||
| 
 | ||||
| export const useBackgroundProcesses = () => { | ||||
|   useWebPushTopicListener(); | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     console.log("[useBackgroundProcesses] mounting"); | ||||
|     startWorkers(); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue