From 421af05882a30692c7563fc46a51ad5b53e81d37 Mon Sep 17 00:00:00 2001 From: redphx <96280+redphx@users.noreply.github.com> Date: Fri, 6 Sep 2024 18:07:13 +0700 Subject: [PATCH] Update TA button's logic & layout in the Guide Menu --- src/assets/css/guide-menu.styl | 34 ++++++++++++++- src/modules/ui/guide-menu.ts | 12 +++++- src/utils/html.ts | 7 +++ src/utils/true-achievements.ts | 79 ++++++++++++++++++++++++++++------ 4 files changed, 116 insertions(+), 16 deletions(-) diff --git a/src/assets/css/guide-menu.styl b/src/assets/css/guide-menu.styl index 69a855f..610efa3 100644 --- a/src/assets/css/guide-menu.styl +++ b/src/assets/css/guide-menu.styl @@ -1,10 +1,40 @@ +.bx-guide-home-achievements-progress { + display: flex; + gap: 10px; + flex-direction: row; + + .bx-button { + margin-bottom: 0 !important; + } + + html[data-xds-platform=tv] & { + flex-direction: column; + } + + html:not([data-xds-platform=tv]) & { + flex-direction: row; + + > button:first-of-type { + flex: 1; + } + + > button:last-of-type { + width: 40px; + + span { + display: none; + } + } + } +} + .bx-guide-home-buttons { > div { display: flex; flex-direction: row; gap: 12px; - body[data-media-type=tv] & { + html[data-xds-platform=tv] & { flex-direction: column; button { @@ -12,7 +42,7 @@ } } - body:not([data-media-type=tv]) & { + html:not([data-xds-platform=tv]) & { button { span { display: none; diff --git a/src/modules/ui/guide-menu.ts b/src/modules/ui/guide-menu.ts index 747fa49..6cec33f 100644 --- a/src/modules/ui/guide-menu.ts +++ b/src/modules/ui/guide-menu.ts @@ -88,7 +88,6 @@ export class GuideMenu { const buttons = [ GuideMenu.#BUTTONS.scriptSettings, [ - TrueAchievements.$button, GuideMenu.#BUTTONS.backToHome, GuideMenu.#BUTTONS.reloadPage, GuideMenu.#BUTTONS.closeApp, @@ -116,6 +115,11 @@ export class GuideMenu { } static #injectHome($root: HTMLElement, isPlaying = false) { + const $achievementsProgress = $root.querySelector('button[class*=AchievementsButton-module__progressBarContainer]'); + if ($achievementsProgress) { + TrueAchievements.injectAchievementsProgress($achievementsProgress as HTMLElement); + } + // Find the element to add buttons to let $target: HTMLElement | null = null; if (isPlaying) { @@ -157,6 +161,12 @@ export class GuideMenu { static observe($addedElm: HTMLElement) { const className = $addedElm.className; + + if (className.includes('AchievementsButton-module__progressBarContainer')) { + TrueAchievements.injectAchievementsProgress($addedElm); + return; + } + if (!className.startsWith('NavigationAnimation') && !className.startsWith('DialogRoutes') && !className.startsWith('Dialog-module__container')) { diff --git a/src/utils/html.ts b/src/utils/html.ts index 10a436d..fb67328 100644 --- a/src/utils/html.ts +++ b/src/utils/html.ts @@ -180,3 +180,10 @@ export function clearFocus() { document.activeElement.blur(); } } + + +export function clearDataSet($elm: HTMLElement) { + Object.keys($elm.dataset).forEach(key => { + delete $elm.dataset[key]; + }); +} diff --git a/src/utils/true-achievements.ts b/src/utils/true-achievements.ts index ec83d26..e17ebd1 100644 --- a/src/utils/true-achievements.ts +++ b/src/utils/true-achievements.ts @@ -1,6 +1,6 @@ import { BxIcon } from "./bx-icon"; import { AppInterface, STATES } from "./global"; -import { ButtonStyle, CE, createButton, getReactProps } from "./html"; +import { ButtonStyle, CE, clearDataSet, createButton, getReactProps } from "./html"; import { t } from "./translation"; export class TrueAchievements { @@ -16,7 +16,7 @@ export class TrueAchievements { label: t('true-achievements'), title: t('true-achievements'), icon: BxIcon.TRUE_ACHIEVEMENTS, - style: ButtonStyle.FOCUSABLE | ButtonStyle.FULL_WIDTH, + style: ButtonStyle.FOCUSABLE, onClick: TrueAchievements.onClick, }) as HTMLAnchorElement; @@ -25,18 +25,67 @@ export class TrueAchievements { const dataset = TrueAchievements.$link.dataset; TrueAchievements.open(true, dataset.xboxTitleId, dataset.id); + + // Close all xCloud's dialogs + window.BX_EXPOSED.dialogRoutes.closeAll(); } private static $hiddenLink = CE('a', { target: '_blank', }); - private static updateLinks(xboxTitleId?: string, id?: string) { - TrueAchievements.$link.dataset.xboxTitleId = xboxTitleId; - TrueAchievements.$link.dataset.id = id; + private static updateIds(xboxTitleId?: string, id?: string) { + const $link = TrueAchievements.$link; + const $button = TrueAchievements.$button; - TrueAchievements.$button.dataset.xboxTitleId = xboxTitleId; - TrueAchievements.$button.dataset.id = id; + clearDataSet($link); + clearDataSet($button); + + if (xboxTitleId) { + $link.dataset.xboxTitleId = xboxTitleId; + $button.dataset.xboxTitleId = xboxTitleId; + } + + if (id) { + $link.dataset.id = id; + $button.dataset.id = id; + } + } + + static injectAchievementsProgress($elm: HTMLElement) { + const $parent = $elm.parentElement!; + + // Wrap xCloud's element with our own + const $div = CE('div', { + class: 'bx-guide-home-achievements-progress', + }, $elm); + + // Get xboxTitleId of the game + let xboxTitleId: string | number | undefined; + try { + const $container = $parent.closest('div[class*=AchievementsPreview-module__container]') as HTMLElement; + if ($container) { + const props = getReactProps($container); + xboxTitleId = props.children.props.data.data.xboxTitleId; + } + } catch (e) {} + + if (!xboxTitleId) { + xboxTitleId = TrueAchievements.getStreamXboxTitleId(); + } + + if (typeof xboxTitleId !== 'undefined') { + xboxTitleId = xboxTitleId.toString(); + } + TrueAchievements.updateIds(xboxTitleId); + + if (document.documentElement.dataset.xdsPlatform === 'tv') { + $div.appendChild(TrueAchievements.$link); + } else { + $div.appendChild(TrueAchievements.$button); + } + + $parent.appendChild($div); } static injectAchievementDetailPage($parent: HTMLElement) { @@ -66,15 +115,19 @@ export class TrueAchievements { // Found achievement -> add TrueAchievements button if (id) { - TrueAchievements.updateLinks(xboxTitleId, id); + TrueAchievements.updateIds(xboxTitleId, id); $parent.appendChild(TrueAchievements.$link); } } catch (e) {}; } + private static getStreamXboxTitleId() : number | undefined { + return STATES.currentStream.xboxTitleId || STATES.currentStream.titleInfo?.details.xboxTitleId; + } + static open(override: boolean, xboxTitleId?: number | string, id?: number | string) { if (!xboxTitleId || xboxTitleId === 'undefined') { - xboxTitleId = STATES.currentStream.xboxTitleId || STATES.currentStream.titleInfo?.details.xboxTitleId; + xboxTitleId = TrueAchievements.getStreamXboxTitleId(); } if (AppInterface && AppInterface.openTrueAchievementsLink) { @@ -84,10 +137,10 @@ export class TrueAchievements { let url = 'https://www.trueachievements.com'; if (xboxTitleId) { - if (id && id !== 'undefined') { - url += `/deeplink/${xboxTitleId}/${id}`; - } else { - url += `/deeplink/${xboxTitleId}`; + url += `/deeplink/${xboxTitleId}`; + + if (id) { + url += `/${id}`; } }