From 3d010ccc011712901fc25e4060a77c37ccc5597c Mon Sep 17 00:00:00 2001 From: pvdstel Date: Wed, 17 Nov 2021 19:20:25 +0100 Subject: [PATCH 1/8] Add a feature flags file --- overwolf/src/logic/featureFlags.ts | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 overwolf/src/logic/featureFlags.ts diff --git a/overwolf/src/logic/featureFlags.ts b/overwolf/src/logic/featureFlags.ts new file mode 100644 index 0000000..9586839 --- /dev/null +++ b/overwolf/src/logic/featureFlags.ts @@ -0,0 +1,3 @@ +const forbiddenFeaturesKey = 'DANGER_ENABLE_FORBIDDEN_FEATURES'; + +export const enableForbiddenFeatures = localStorage.getItem(forbiddenFeaturesKey) === true.toString(); From 120100bf3a3e995b197e8b52c24e866ed468e05d Mon Sep 17 00:00:00 2001 From: pvdstel Date: Wed, 17 Nov 2021 19:22:39 +0100 Subject: [PATCH 2/8] Disable rendering forbidden features --- overwolf/src/Minimap/useMinimapRenderer.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/overwolf/src/Minimap/useMinimapRenderer.ts b/overwolf/src/Minimap/useMinimapRenderer.ts index 61ff12c..99e168d 100644 --- a/overwolf/src/Minimap/useMinimapRenderer.ts +++ b/overwolf/src/Minimap/useMinimapRenderer.ts @@ -1,5 +1,6 @@ import React, { useContext, useEffect, useRef, useState } from 'react'; import { AppContext } from '@/contexts/AppContext'; +import { enableForbiddenFeatures } from '@/logic/featureFlags'; import { FriendData } from '@/logic/friends'; import MapIconsCache from '@/logic/mapIconsCache'; import { store, zoomLevelSettingBounds } from '@/logic/storage'; @@ -172,11 +173,13 @@ export default function useMinimapRenderer(canvas: React.RefObject Date: Wed, 17 Nov 2021 19:29:33 +0100 Subject: [PATCH 3/8] Split up into feature flags --- overwolf/src/Minimap/drawMapFriends.ts | 5 +++++ overwolf/src/Minimap/drawMapLabels.ts | 5 +++++ overwolf/src/Minimap/drawMapMarkers.ts | 5 +++++ overwolf/src/Minimap/drawMapNavigation.ts | 7 ++++++- overwolf/src/Minimap/drawMapNavigationTarget.ts | 5 +++++ overwolf/src/Minimap/useMinimapRenderer.ts | 9 +++------ overwolf/src/logic/featureFlags.ts | 7 ++++++- 7 files changed, 35 insertions(+), 8 deletions(-) diff --git a/overwolf/src/Minimap/drawMapFriends.ts b/overwolf/src/Minimap/drawMapFriends.ts index 1fbdf3a..2a3128f 100644 --- a/overwolf/src/Minimap/drawMapFriends.ts +++ b/overwolf/src/Minimap/drawMapFriends.ts @@ -1,3 +1,4 @@ +import { canDrawFriends } from '@/logic/featureFlags'; import { FriendData } from '@/logic/friends'; import { worldCoordinateToCanvas } from '@/logic/tiles'; import { rotateAround } from '@/logic/util'; @@ -7,6 +8,10 @@ import { MapIconRendererParameters, MapRendererParameters } from './useMinimapRe const sliceRotationOffset = -Math.PI / 2; export default function drawMapFriends(params: MapRendererParameters, iconParams: MapIconRendererParameters, friends: FriendData[]) { + if (!canDrawFriends) { + return; + } + const { context: ctx, center, diff --git a/overwolf/src/Minimap/drawMapLabels.ts b/overwolf/src/Minimap/drawMapLabels.ts index 3e5db8e..13a25a9 100644 --- a/overwolf/src/Minimap/drawMapLabels.ts +++ b/overwolf/src/Minimap/drawMapLabels.ts @@ -1,4 +1,5 @@ import React from 'react'; +import { canDrawMarkers } from '@/logic/featureFlags'; import { getIconName } from '@/logic/icons'; import { getMarkers } from '@/logic/markers'; import { canvasCoordinateToWorld, getTileCoordinatesForWorldCoordinate, worldCoordinateToCanvas } from '@/logic/tiles'; @@ -22,6 +23,10 @@ export default function drawMapLabel(ctx: CanvasRenderingContext2D, marker: Mark } export function drawMapHoverLabel(mousePos: Vector2, lastDrawCache: LastDrawParameters, canvas: React.RefObject, iconScale: number) { + if (!canDrawMarkers) { + return; + } + if (!canvas.current) { return; } diff --git a/overwolf/src/Minimap/drawMapMarkers.ts b/overwolf/src/Minimap/drawMapMarkers.ts index 4dbd651..ee39d3b 100644 --- a/overwolf/src/Minimap/drawMapMarkers.ts +++ b/overwolf/src/Minimap/drawMapMarkers.ts @@ -1,9 +1,14 @@ +import { canDrawMarkers } from '@/logic/featureFlags'; import { worldCoordinateToCanvas } from '@/logic/tiles'; import { rotateAround } from '@/logic/util'; import drawMapLabel from '@/Minimap/drawMapLabels'; import { MapIconRendererParameters, MapRendererParameters } from './useMinimapRenderer'; export default function drawMapMarkers(params: MapRendererParameters, iconParams: MapIconRendererParameters, markers: Marker[]) { + if (!canDrawMarkers) { + return; + } + const { context: ctx, center, diff --git a/overwolf/src/Minimap/drawMapNavigation.ts b/overwolf/src/Minimap/drawMapNavigation.ts index 82be5fc..81c1339 100644 --- a/overwolf/src/Minimap/drawMapNavigation.ts +++ b/overwolf/src/Minimap/drawMapNavigation.ts @@ -1,10 +1,15 @@ +import { canDrawNavigation } from '@/logic/featureFlags'; import { getNavPath } from '@/logic/navigation/navigation'; import { worldCoordinateToCanvas } from '@/logic/tiles'; import { rotateAround } from '@/logic/util'; import setLineStyle from './setLineStyle'; import { MapRendererParameters } from './useMinimapRenderer'; -export default function drawMapNavigation(params: MapRendererParameters) { +export default function drawMapNavigation(params: MapRendererParameters): Vector2 | undefined { + if (!canDrawNavigation) { + return undefined; + } + const { context: ctx, center, diff --git a/overwolf/src/Minimap/drawMapNavigationTarget.ts b/overwolf/src/Minimap/drawMapNavigationTarget.ts index 7602e2b..ae42c65 100644 --- a/overwolf/src/Minimap/drawMapNavigationTarget.ts +++ b/overwolf/src/Minimap/drawMapNavigationTarget.ts @@ -1,6 +1,11 @@ +import { canDrawNavigation } from '@/logic/featureFlags'; import { MapIconRendererParameters, MapRendererParameters } from './useMinimapRenderer'; export default function drawMapNavigationTarget(params: MapRendererParameters, iconParams: MapIconRendererParameters, target: Vector2 | undefined) { + if (!canDrawNavigation) { + return; + } + if (!target) { return; } diff --git a/overwolf/src/Minimap/useMinimapRenderer.ts b/overwolf/src/Minimap/useMinimapRenderer.ts index 99e168d..61ff12c 100644 --- a/overwolf/src/Minimap/useMinimapRenderer.ts +++ b/overwolf/src/Minimap/useMinimapRenderer.ts @@ -1,6 +1,5 @@ import React, { useContext, useEffect, useRef, useState } from 'react'; import { AppContext } from '@/contexts/AppContext'; -import { enableForbiddenFeatures } from '@/logic/featureFlags'; import { FriendData } from '@/logic/friends'; import MapIconsCache from '@/logic/mapIconsCache'; import { store, zoomLevelSettingBounds } from '@/logic/storage'; @@ -173,13 +172,11 @@ export default function useMinimapRenderer(canvas: React.RefObject Date: Wed, 17 Nov 2021 19:35:15 +0100 Subject: [PATCH 4/8] Disable navigation button --- overwolf/src/MinimapToolbarIconButton.tsx | 6 +++++- overwolf/src/MinimapToolbars.tsx | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/overwolf/src/MinimapToolbarIconButton.tsx b/overwolf/src/MinimapToolbarIconButton.tsx index 2c0437f..556dc88 100644 --- a/overwolf/src/MinimapToolbarIconButton.tsx +++ b/overwolf/src/MinimapToolbarIconButton.tsx @@ -29,7 +29,7 @@ const useStyles = makeStyles()(theme => ({ pointerEvents: 'none', // makes tooltips behave nicer }, - '&:hover': { + '&:hover:not(:disabled)': { background: theme.buttonBackgroundHover, }, @@ -41,6 +41,10 @@ const useStyles = makeStyles()(theme => ({ '&:active': { background: theme.buttonBackgroundPress, }, + + '&:disabled': { + opacity: 0.5, + }, }, selected: { // background: theme.buttonBackgroundHover, diff --git a/overwolf/src/MinimapToolbars.tsx b/overwolf/src/MinimapToolbars.tsx index 9dd1690..7e600bd 100644 --- a/overwolf/src/MinimapToolbars.tsx +++ b/overwolf/src/MinimapToolbars.tsx @@ -8,6 +8,7 @@ import DragIcon from './Icons/DragIcon'; import RecenterIcon from './Icons/RecenterIcon'; import ZoomInIcon from './Icons/ZoomInIcon'; import ZoomOutIcon from './Icons/ZoomOutIcon'; +import { canDrawNavigation } from './logic/featureFlags'; import MinimapToolbar from './MinimapToolbar'; import MinimapToolbarIconButton from './MinimapToolbarIconButton'; import { makeStyles } from './theme'; @@ -90,6 +91,7 @@ export default function MinimapToolbars(props: IProps) { isSelected={interactionMode === 'destination'} onClick={() => setInteractionMode('destination')} title={t('minimap.mode_destination')} + disabled={!canDrawNavigation} > From adaa0692567ec081a2bbce034f8ab1ef713b8ad9 Mon Sep 17 00:00:00 2001 From: pvdstel Date: Wed, 17 Nov 2021 19:46:03 +0100 Subject: [PATCH 5/8] Move settings refreshing to App --- overwolf/src/App.tsx | 48 ++++++++++++++++++++++++++ overwolf/src/Frame.tsx | 51 ++++------------------------ overwolf/src/contexts/AppContext.tsx | 2 +- 3 files changed, 56 insertions(+), 45 deletions(-) diff --git a/overwolf/src/App.tsx b/overwolf/src/App.tsx index 7b4b418..8262f56 100644 --- a/overwolf/src/App.tsx +++ b/overwolf/src/App.tsx @@ -1,6 +1,8 @@ +import produce from 'immer'; import React, { useContext, useEffect } from 'react'; import { AppContext } from './contexts/AppContext'; import { getDefaultIconSettings } from './logic/markers'; +import { deconstructIconStorageKey, getStorageKeyScope, load, loadIconConfiguration, scopedSettings, simpleStorageDefaultSettings, SimpleStorageSetting } from './logic/storage'; import Minimap from './Minimap'; import { makeStyles } from './theme'; import Welcome from './Welcome'; @@ -33,6 +35,52 @@ export default function App() { }); }, []); + useEffect(() => { + function handleStorageEvent(e: StorageEvent) { + if (!e.key || !e.newValue) { return; } + + const [keyScope, identifier] = getStorageKeyScope(e.key); + if (keyScope === NWMM_APP_WINDOW && scopedSettings.includes(identifier as keyof SimpleStorageSetting)) { + // The setting is scoped to the current window, and is listed as a scoped setting + context.update({ [identifier as keyof SimpleStorageSetting]: load(identifier as keyof SimpleStorageSetting) }); + } else if (keyScope === 'icon') { + // It is an icon setting. First, determine if it's just a category, or a category and an icon + const iconSetting = deconstructIconStorageKey(identifier); + if (iconSetting) { + const { category, type, property } = iconSetting; + if (type) { + // It is a category and type. If the iconSettings are loaded, and the category and type exist, + // produce a new iconSettings with the category.types.type value set to the new setting value. + context.update(prev => produce(prev, draft => { + const setting = draft.iconSettings?.categories[category]?.types[type]; + if (setting) { + setting[property] = loadIconConfiguration(category, type, property); + } + })); + } else { + // It is just a category. If the iconSettings are loaded, and the category exists, produce a new iconSettings + // with the category value set to the new setting value. + context.update(prev => produce(prev, draft => { + const setting = draft.iconSettings?.categories[category]; + if (setting) { + setting[property] = loadIconConfiguration(category, type, property); + } + })); + } + } + } else if (keyScope === undefined && simpleStorageDefaultSettings.hasOwnProperty(identifier) && !scopedSettings.includes(identifier as keyof SimpleStorageSetting)) { + // The setting is not scoped to the current window, and exists, but is not listed as a scoped setting. + context.update({ [identifier as keyof SimpleStorageSetting]: load(identifier as keyof SimpleStorageSetting) }); + } + } + + window.addEventListener('storage', handleStorageEvent); + + return () => { + window.removeEventListener('storage', handleStorageEvent); + }; + }, []); + if (!context.gameRunning) { return ; } diff --git a/overwolf/src/Frame.tsx b/overwolf/src/Frame.tsx index a6e0ac8..d10e8d0 100644 --- a/overwolf/src/Frame.tsx +++ b/overwolf/src/Frame.tsx @@ -1,12 +1,10 @@ import '@/style/lato-fonts.css'; import clsx from 'clsx'; -import produce from 'immer'; import React, { useCallback, useEffect, useState } from 'react'; import { GlobalStyles } from 'tss-react'; import App from './App'; import AppSettings from './AppSettings/AppSettings'; import { AppContext, AppContextSettings, IAppContext, loadAppContextSettings } from './contexts/AppContext'; -import { deconstructIconStorageKey, getStorageKeyScope, load, loadIconConfiguration, scopedSettings, simpleStorageDefaultSettings, SimpleStorageSetting } from './logic/storage'; import { getBackgroundController } from './OverwolfWindows/background/background'; import { makeStyles, theme } from './theme'; @@ -46,54 +44,19 @@ export default function Frame(props: IProps) { const [appContextSettings, setAppContextSettings] = useState(loadAppContextSettings); const [gameRunning, setGameRunning] = useState(backgroundController.gameRunning); - const updateAppContext = useCallback((e: Partial) => setAppContextSettings(prev => ({ ...prev, ...e })), []); + const updateAppContext = useCallback((e: React.SetStateAction>) => { + if (typeof e === 'function') { + setAppContextSettings(prev => ({ ...prev, ...e(prev) })); + } else { + setAppContextSettings(prev => ({ ...prev, ...e })); + } + }, []); const toggleFrameMenu = useCallback(() => setAppSettingsVisible(prev => !prev), []); useEffect(() => { - function handleStorageEvent(e: StorageEvent) { - if (!e.key || !e.newValue) { return; } - - const [keyScope, identifier] = getStorageKeyScope(e.key); - if (keyScope === NWMM_APP_WINDOW && scopedSettings.includes(identifier as keyof SimpleStorageSetting)) { - // The setting is scoped to the current window, and is listed as a scoped setting - updateAppContext({ [identifier as keyof SimpleStorageSetting]: load(identifier as keyof SimpleStorageSetting) }); - } else if (keyScope === 'icon') { - // It is an icon setting. First, determine if it's just a category, or a category and an icon - const iconSetting = deconstructIconStorageKey(identifier); - if (iconSetting) { - const { category, type, property } = iconSetting; - if (type) { - // It is a category and type. If the iconSettings are loaded, and the category and type exist, - // produce a new iconSettings with the category.types.type value set to the new setting value. - setAppContextSettings(prev => produce(prev, draft => { - const setting = draft.iconSettings?.categories[category]?.types[type]; - if (setting) { - setting[property] = loadIconConfiguration(category, type, property); - } - })); - } else { - // It is just a category. If the iconSettings are loaded, and the category exists, produce a new iconSettings - // with the category value set to the new setting value. - setAppContextSettings(prev => produce(prev, draft => { - const setting = draft.iconSettings?.categories[category]; - if (setting) { - setting[property] = loadIconConfiguration(category, type, property); - } - })); - } - } - } else if (keyScope === undefined && simpleStorageDefaultSettings.hasOwnProperty(identifier) && !scopedSettings.includes(identifier as keyof SimpleStorageSetting)) { - // The setting is not scoped to the current window, and exists, but is not listed as a scoped setting. - updateAppContext({ [identifier as keyof SimpleStorageSetting]: load(identifier as keyof SimpleStorageSetting) }); - } - } - - window.addEventListener('storage', handleStorageEvent); - const gameRunningListenRegistration = backgroundController.listenOnGameRunningChange(setGameRunning, window); return () => { - window.removeEventListener('storage', handleStorageEvent); gameRunningListenRegistration(); }; }, []); diff --git a/overwolf/src/contexts/AppContext.tsx b/overwolf/src/contexts/AppContext.tsx index 54c08a5..c23ffc6 100644 --- a/overwolf/src/contexts/AppContext.tsx +++ b/overwolf/src/contexts/AppContext.tsx @@ -7,7 +7,7 @@ export type AppContextSettings = SimpleStorageSetting & { export interface IAppContext { settings: AppContextSettings; - update: (delta: Partial) => void; + update: (delta: React.SetStateAction>) => void; toggleFrameMenu: () => void; gameRunning: boolean; isTransparentSurface: boolean | undefined; From a6f343747ab775fdb25ceacaf58780934aa63ec8 Mon Sep 17 00:00:00 2001 From: pvdstel Date: Wed, 17 Nov 2021 20:08:36 +0100 Subject: [PATCH 6/8] Add global notice to the app --- overwolf/src/Frame.tsx | 2 + overwolf/src/InAppNotices.tsx | 89 +++++++++++++++++++++++++++++++++++ overwolf/src/globalLayers.ts | 3 +- 3 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 overwolf/src/InAppNotices.tsx diff --git a/overwolf/src/Frame.tsx b/overwolf/src/Frame.tsx index d10e8d0..48e5c4d 100644 --- a/overwolf/src/Frame.tsx +++ b/overwolf/src/Frame.tsx @@ -5,6 +5,7 @@ import { GlobalStyles } from 'tss-react'; import App from './App'; import AppSettings from './AppSettings/AppSettings'; import { AppContext, AppContextSettings, IAppContext, loadAppContextSettings } from './contexts/AppContext'; +import InAppNotices from './InAppNotices'; import { getBackgroundController } from './OverwolfWindows/background/background'; import { makeStyles, theme } from './theme'; @@ -120,6 +121,7 @@ export default function Frame(props: IProps) { onClose={() => setAppSettingsVisible(false)} /> {header} + diff --git a/overwolf/src/InAppNotices.tsx b/overwolf/src/InAppNotices.tsx new file mode 100644 index 0000000..1c409b0 --- /dev/null +++ b/overwolf/src/InAppNotices.tsx @@ -0,0 +1,89 @@ +import React, { useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import Button from './Button'; +import { globalLayers } from './globalLayers'; +import { makeStyles } from './theme'; + +const notices = { + '5289534c-bf5a-4d5c-8678-254ab8bdefe3': 'Due to requests from Amazon Games, several features of this application have been disabled until further notice. These features include:\n\n- Markers on the map\n- Navigation\n- Displaying friends.\n\nWe will consider enabling them when the APIs we need to display the correct information are available.', +}; + +function loadNoticeRead(notice: keyof typeof notices) { + return localStorage.getItem(`notice::${notice}`) === true.toString(); +} + +function storeNoticeRead(notice: keyof typeof notices) { + localStorage.setItem(`notice::${notice}`, true.toString()); +} + +const useStyles = makeStyles()(theme => ({ + root: { + background: '#343f6e', + color: theme.color, + position: 'fixed', + top: 0, + left: 0, + right: 0, + bottom: 0, + zIndex: globalLayers.inAppAnnouncement, + + display: 'flex', + flexDirection: 'column', + alignItems: 'center', + padding: theme.spacing(1), + gap: theme.spacing(1), + }, + notices: { + flexGrow: 1, + maxWidth: '100%', + width: 500, + marginTop: theme.spacing(5), + overflow: 'auto', + }, + notice: { + padding: theme.spacing(1), + + '&:not(:last-child)': { + borderBottom: `1px solid ${theme.color}`, + }, + }, + noticeText: { + whiteSpace: 'pre-line', + }, + actions: { + + }, +})); + +export default function InAppNotices() { + const { classes } = useStyles(); + const { t } = useTranslation(); + + const forceRerender = useState(0)[1]; + const noticeEntries = Object.entries(notices) as [keyof typeof notices, string][]; + const unreadNotices = noticeEntries.filter(ne => !loadNoticeRead(ne[0])); + + if (unreadNotices.length === 0) { + return null; + } + + function handleClose() { + for (const unreadNotice of unreadNotices) { + storeNoticeRead(unreadNotice[0]); + } + forceRerender(value => value + 1); + } + + return
+
+ {unreadNotices.map(n =>
+

+ {n[1]} +

+
)} +
+
+ +
+
; +} diff --git a/overwolf/src/globalLayers.ts b/overwolf/src/globalLayers.ts index df9fac4..06bacfa 100644 --- a/overwolf/src/globalLayers.ts +++ b/overwolf/src/globalLayers.ts @@ -1,9 +1,10 @@ export const globalLayers = { - frameMenu: 975, + frameMenu: 900, header: 950, minimapCanvas: 10, minimapHoverCanvas: 11, minimapCacheStatus: 12, minimapToolbar: 15, resizeGrips: 999, + inAppAnnouncement: 940, }; From a093cb14f5d68d12812dd121c904fd3a7c146753 Mon Sep 17 00:00:00 2001 From: pvdstel Date: Wed, 17 Nov 2021 20:24:49 +0100 Subject: [PATCH 7/8] Bump version to 1.3.0 --- overwolf/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/overwolf/package.json b/overwolf/package.json index 1ac49b4..c84545d 100644 --- a/overwolf/package.json +++ b/overwolf/package.json @@ -1,6 +1,6 @@ { "name": "cptwesley-minimap", - "version": "1.2.0", + "version": "1.3.0", "description": "", "main": "index.js", "scripts": { From e70fde3f714e8516b1f77db95fb9d6d5844e3e56 Mon Sep 17 00:00:00 2001 From: pvdstel Date: Wed, 17 Nov 2021 20:25:38 +0100 Subject: [PATCH 8/8] Also bump manifest to 1.3.0 --- overwolf/public/manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/overwolf/public/manifest.json b/overwolf/public/manifest.json index f8ec547..d23402e 100644 --- a/overwolf/public/manifest.json +++ b/overwolf/public/manifest.json @@ -4,7 +4,7 @@ "meta": { "name": "CptWesley's Minimap", "author": "Wesley Baartman", - "version": "1.2.0", + "version": "1.3.0", "minimum-overwolf-version": "0.92.300.0", "description": "Open-source minimap for Amazon's New World.", "dock_button_title": "CptWesleys Minimap",