From 6a792548fa7e7001ce5c04dd53665e05b1b5d911 Mon Sep 17 00:00:00 2001 From: redphx <96280+redphx@users.noreply.github.com> Date: Wed, 4 Sep 2024 19:44:41 +0700 Subject: [PATCH] Update TrueAchievements button in Guide Menu --- src/index.ts | 30 +++++----------------- src/modules/ui/guide-menu.ts | 47 +++++++++++++++++++++++----------- src/utils/bx-event.ts | 4 +++ src/utils/bx-flags.ts | 4 +++ src/utils/true-achievements.ts | 46 ++++++++++++++++++++++----------- 5 files changed, 77 insertions(+), 54 deletions(-) diff --git a/src/index.ts b/src/index.ts index 6b488a5..24f1eb7 100644 --- a/src/index.ts +++ b/src/index.ts @@ -326,36 +326,18 @@ function observeRootDialog($root: HTMLElement) { continue; } - console.log('added', mutation.addedNodes); + BX_FLAGS.Debug && BxLogger.warning('RootDialog', 'added', mutation.addedNodes); if (mutation.addedNodes.length === 1) { const $addedElm = mutation.addedNodes[0]; if ($addedElm instanceof HTMLElement && $addedElm.className) { - if ($addedElm.className.startsWith('NavigationAnimation') || $addedElm.className.startsWith('DialogRoutes') || $addedElm.className.startsWith('Dialog-module__container')) { - // Make sure it's Guide dialog - if (document.querySelector('#gamepass-dialog-root div[class*=GuideDialog]')) { - // Achievement Details page - const $achievDetailPage = $addedElm.querySelector('div[class*=AchievementDetailPage]'); - if ($achievDetailPage) { - TrueAchievements.injectAchievementDetailPage($achievDetailPage as HTMLElement); - } else { - // Find navigation bar - const $selectedTab = $addedElm.querySelector('div[class^=NavigationMenu] button[aria-selected=true'); - if ($selectedTab) { - let $elm: Element | null = $selectedTab; - let index; - for (index = 0; ($elm = $elm?.previousElementSibling); index++); - - if (index === 0) { - BxEvent.dispatch(window, BxEvent.XCLOUD_GUIDE_MENU_SHOWN, {where: GuideMenuTab.HOME}); - } - } - } - } + // Make sure it's Guide dialog + if ($root.querySelector('div[class*=GuideDialog]')) { + GuideMenu.observe($addedElm); } } } - const shown = ($root.firstElementChild && $root.firstElementChild.childElementCount > 0) || false; + const shown = !!($root.firstElementChild && $root.firstElementChild.childElementCount > 0); if (shown !== beingShown) { beingShown = shown; BxEvent.dispatch(window, shown ? BxEvent.XCLOUD_DIALOG_SHOWN : BxEvent.XCLOUD_DIALOG_DISMISSED); @@ -416,7 +398,7 @@ function main() { (getPref(PrefKey.GAME_BAR_POSITION) !== 'off') && GameBar.getInstance(); Screenshot.setup(); - GuideMenu.observe(); + GuideMenu.addEventListeners(); StreamBadges.setupEvents(); StreamStats.setupEvents(); EmulatedMkbHandler.setupEvents(); diff --git a/src/modules/ui/guide-menu.ts b/src/modules/ui/guide-menu.ts index d146b8d..618b515 100644 --- a/src/modules/ui/guide-menu.ts +++ b/src/modules/ui/guide-menu.ts @@ -42,7 +42,7 @@ export class GuideMenu { reloadPage: createButton({ icon: BxIcon.REFRESH, title: t('reload-page'), - style: ButtonStyle.FULL_WIDTH | ButtonStyle.FOCUSABLE | ButtonStyle.GHOST, + style: ButtonStyle.FULL_WIDTH | ButtonStyle.FOCUSABLE, onClick: e => { if (STATES.isPlaying) { confirm(t('confirm-reload-stream')) && window.location.reload(); @@ -58,7 +58,7 @@ export class GuideMenu { backToHome: createButton({ icon: BxIcon.HOME, title: t('back-to-home'), - style: ButtonStyle.FULL_WIDTH | ButtonStyle.FOCUSABLE | ButtonStyle.GHOST, + style: ButtonStyle.FULL_WIDTH | ButtonStyle.FOCUSABLE, onClick: e => { confirm(t('back-to-home-confirm')) && (window.location.href = window.location.href.substring(0, 31)); @@ -69,17 +69,6 @@ export class GuideMenu { 'data-state': 'playing', }, }), - - trueAchievements: createButton({ - label: t('true-achievements'), - style: ButtonStyle.FULL_WIDTH | ButtonStyle.FOCUSABLE, - onClick: e => { - TrueAchievements.open(false); - - // Close all xCloud's dialogs - window.BX_EXPOSED.dialogRoutes.closeAll(); - }, - }), } static #$renderedButtons: HTMLElement; @@ -95,8 +84,8 @@ export class GuideMenu { const buttons = [ GuideMenu.#BUTTONS.scriptSettings, - GuideMenu.#BUTTONS.trueAchievements, [ + TrueAchievements.$button, GuideMenu.#BUTTONS.backToHome, GuideMenu.#BUTTONS.reloadPage, GuideMenu.#BUTTONS.closeApp, @@ -159,7 +148,35 @@ export class GuideMenu { } } - static observe() { + static addEventListeners() { window.addEventListener(BxEvent.XCLOUD_GUIDE_MENU_SHOWN, GuideMenu.#onShown); } + + static observe($addedElm: HTMLElement) { + const className = $addedElm.className; + if (!className.startsWith('NavigationAnimation') && + !className.startsWith('DialogRoutes') && + !className.startsWith('Dialog-module__container')) { + return; + } + + // Achievement Details page + const $achievDetailPage = $addedElm.querySelector('div[class*=AchievementDetailPage]'); + if ($achievDetailPage) { + TrueAchievements.injectAchievementDetailPage($achievDetailPage as HTMLElement); + return; + } + + // Find navigation bar + const $selectedTab = $addedElm.querySelector('div[class^=NavigationMenu] button[aria-selected=true'); + if ($selectedTab) { + let $elm: Element | null = $selectedTab; + let index; + for (index = 0; ($elm = $elm?.previousElementSibling); index++); + + if (index === 0) { + BxEvent.dispatch(window, BxEvent.XCLOUD_GUIDE_MENU_SHOWN, {where: GuideMenuTab.HOME}); + } + } + } } diff --git a/src/utils/bx-event.ts b/src/utils/bx-event.ts index 736339f..5b4d2d8 100644 --- a/src/utils/bx-event.ts +++ b/src/utils/bx-event.ts @@ -1,4 +1,6 @@ import { AppInterface } from "@utils/global"; +import { BxLogger } from "./bx-logger"; +import { BX_FLAGS } from "./bx-flags"; export namespace BxEvent { @@ -75,6 +77,8 @@ export namespace BxEvent { target.dispatchEvent(event); AppInterface && AppInterface.onEvent(eventName); + + BX_FLAGS.Debug && BxLogger.warning('BxEvent', 'dispatch', eventName, data) } } diff --git a/src/utils/bx-flags.ts b/src/utils/bx-flags.ts index 7d244d2..327a236 100644 --- a/src/utils/bx-flags.ts +++ b/src/utils/bx-flags.ts @@ -1,6 +1,8 @@ import { BxLogger } from "./bx-logger"; type BxFlags = { + Debug: boolean; + CheckForUpdate: boolean; EnableXcloudLogging: boolean; SafariWorkaround: boolean; @@ -20,6 +22,8 @@ type BxFlags = { // Setup flags const DEFAULT_FLAGS: BxFlags = { + Debug: false, + CheckForUpdate: true, EnableXcloudLogging: false, SafariWorkaround: true, diff --git a/src/utils/true-achievements.ts b/src/utils/true-achievements.ts index bc4e476..9e9320d 100644 --- a/src/utils/true-achievements.ts +++ b/src/utils/true-achievements.ts @@ -1,24 +1,43 @@ +import { BxIcon } from "./bx-icon"; import { AppInterface, STATES } from "./global"; import { ButtonStyle, CE, createButton, getReactProps } from "./html"; import { t } from "./translation"; export class TrueAchievements { - private static $taLink = createButton({ + private static $link = createButton({ label: t('true-achievements'), - url: 'https://www.trueachievements.com', + url: '#', + icon: BxIcon.TRUE_ACHIEVEMENTS, style: ButtonStyle.FOCUSABLE | ButtonStyle.GHOST | ButtonStyle.FULL_WIDTH | ButtonStyle.NORMAL_LINK, - onClick: e => { - e.preventDefault(); - - const dataset = TrueAchievements.$taLink.dataset; - TrueAchievements.open(true, dataset.xboxTitleId, dataset.id); - }, + onClick: TrueAchievements.onClick, }) as HTMLAnchorElement; + static $button = createButton({ + title: t('true-achievements'), + icon: BxIcon.TRUE_ACHIEVEMENTS, + style: ButtonStyle.FOCUSABLE | ButtonStyle.FULL_WIDTH, + onClick: TrueAchievements.onClick, + }) as HTMLAnchorElement; + + private static onClick(e: Event) { + e.preventDefault(); + + const dataset = TrueAchievements.$link.dataset; + TrueAchievements.open(true, dataset.xboxTitleId, dataset.id); + } + private static $hiddenLink = CE('a', { target: '_blank', }); + private static updateLinks(xboxTitleId?: string, id?: string) { + TrueAchievements.$link.dataset.xboxTitleId = xboxTitleId; + TrueAchievements.$link.dataset.id = id; + + TrueAchievements.$button.dataset.xboxTitleId = xboxTitleId; + TrueAchievements.$button.dataset.id = id; + } + static injectAchievementDetailPage($parent: HTMLElement) { const props = getReactProps($parent); if (!props) { @@ -46,17 +65,14 @@ export class TrueAchievements { // Found achievement -> add TrueAchievements button if (id) { - TrueAchievements.$taLink.dataset.xboxTitleId = xboxTitleId; - TrueAchievements.$taLink.dataset.id = id; - - TrueAchievements.$taLink.href = `https://www.trueachievements.com/deeplink/${xboxTitleId}/${id}`; - $parent.appendChild(TrueAchievements.$taLink); + TrueAchievements.updateLinks(xboxTitleId, id); + $parent.appendChild(TrueAchievements.$link); } } catch (e) {}; } static open(override: boolean, xboxTitleId?: number | string, id?: number | string) { - if (!xboxTitleId) { + if (!xboxTitleId || xboxTitleId === 'undefined') { xboxTitleId = STATES.currentStream.xboxTitleId || STATES.currentStream.titleInfo?.details.xboxTitleId; } @@ -67,7 +83,7 @@ export class TrueAchievements { let url = 'https://www.trueachievements.com'; if (xboxTitleId) { - if (id) { + if (id && id !== 'undefined') { url += `/deeplink/${xboxTitleId}/${id}`; } else { url += `/deeplink/${xboxTitleId}`;