// // hero-carousel-overlay-common.ts // AppStoreKit // // Created by Jonathan Ellenbogen on 12/11/20. // Copyright (c) 2016 Apple Inc. All rights reserved. // import * as models from "../../../api/models"; import * as serverData from "../../../foundation/json-parsing/server-data"; import * as mediaAttributes from "../../../foundation/media/attributes"; import * as mediaDataStructure from "../../../foundation/media/data-structure"; import * as mediaRelationship from "../../../foundation/media/relationships"; import * as color from "../../../foundation/util/color-util"; import * as breakoutsCommon from "../../arcade/breakouts-common"; import * as contentAttributes from "../../content/attributes"; import * as content from "../../content/content"; import * as lockups from "../../lockups/lockups"; import * as metricsHelpersClicks from "../../metrics/helpers/clicks"; import * as metricsHelpersImpressions from "../../metrics/helpers/impressions"; import * as heroCommon from "./hero-common"; import * as lottery from "../../util/lottery"; export function overlayFromData(objectGraph, data, requirements) { const heroCarouselItemOverlay = new models.HeroCarouselItemOverlay(); heroCarouselItemOverlay.overlayType = overlayTypeFromData(objectGraph, data); heroCarouselItemOverlay.displayOptions = { horizontalPlacement: overlayPlacementFromData(objectGraph, data), textAlignment: overlayTextAlignmentFromData(objectGraph, data), isOverDarkContent: overlayIsOverDarkContent(objectGraph, data), }; const primaryContent = content.primaryContentForData(objectGraph, data); // If this EI can and should show the expected release date of an app, override the badge. const fallbackLabel = mediaAttributes.attributeAsString(data, "label"); if (contentAttributes.contentAttributeAsBooleanOrFalse(objectGraph, data, "showExpectedReleaseDate")) { heroCarouselItemOverlay.badgeText = objectGraph.loc.uppercased(content.dynamicPreorderDateFromData(objectGraph, primaryContent, fallbackLabel)); } else { heroCarouselItemOverlay.badgeText = fallbackLabel; } heroCarouselItemOverlay.titleText = content.editorialNotesFromData(objectGraph, data, "name") || contentAttributes.contentAttributeAsString(objectGraph, primaryContent, "name"); if (heroCarouselItemOverlay.overlayType === "singleModule" || heroCarouselItemOverlay.overlayType === "collectionModule") { heroCarouselItemOverlay.descriptionText = content.editorialNotesFromData(objectGraph, data, "tagline"); } else { heroCarouselItemOverlay.descriptionText = content.editorialNotesFromData(objectGraph, data, "short") || contentAttributes.contentAttributeAsString(objectGraph, primaryContent, "tagline"); } heroCarouselItemOverlay.callToActionText = mediaAttributes.attributeAsString(data, "breakoutCallToActionLabel"); heroCarouselItemOverlay.buttonTitle = overlayButtonTitleFromData(objectGraph, data); if (heroCarouselItemOverlay.overlayType === "lockup" || heroCarouselItemOverlay.overlayType === "singleModule") { heroCarouselItemOverlay.lockup = overlayLockupFromData(objectGraph, data, requirements); } // For hero items the design is to use editorial labels instead of "Apple Arcade" so we replace that text here if ((fallbackLabel === null || fallbackLabel === void 0 ? void 0 : fallbackLabel.length) > 0 && serverData.isDefinedNonNull(heroCarouselItemOverlay.lockup)) { heroCarouselItemOverlay.lockup.heading = fallbackLabel; } heroCarouselItemOverlay.collectionIcons = overlayCollectionIconsFromData(objectGraph, data); if (serverData.isDefinedNonNullNonEmpty(heroCarouselItemOverlay.lockup)) { heroCarouselItemOverlay.clickAction = heroCarouselItemOverlay.lockup.clickAction; heroCarouselItemOverlay.impressionMetrics = heroCarouselItemOverlay.lockup.impressionMetrics; } else { const heroCarouselItemOverlayMetricsOptions = { targetType: "lockup", pageInformation: requirements.metricsPageInformation, locationTracker: requirements.metricsLocationTracker, recoMetricsData: mediaDataStructure.metricsFromMediaApiObject(data), }; const overlayMetricsTitle = heroCarouselItemTitleFromData(objectGraph, data); const heroCarouselItemOverlayAction = breakoutsCommon.actionFromData(objectGraph, data); heroCarouselItemOverlayAction.title = overlayMetricsTitle; const heroCarouselItemOverlayClickOptions = { pageInformation: requirements.metricsPageInformation, locationTracker: requirements.metricsLocationTracker, recoMetricsData: mediaDataStructure.metricsFromMediaApiObject(data), targetType: "lockup", id: data.id, }; metricsHelpersClicks.addClickEventToAction(objectGraph, heroCarouselItemOverlayAction, heroCarouselItemOverlayClickOptions); heroCarouselItemOverlay.clickAction = heroCarouselItemOverlayAction; const heroCarouselItemOverlayImpressionsOptions = metricsHelpersImpressions.impressionOptions(objectGraph, data, overlayMetricsTitle, heroCarouselItemOverlayMetricsOptions); metricsHelpersImpressions.addImpressionFields(objectGraph, heroCarouselItemOverlay, heroCarouselItemOverlayImpressionsOptions); } return heroCarouselItemOverlay; } export function overlayTypeFromData(objectGraph, data) { const displayMaterial = mediaAttributes.attributeAsBooleanOrFalse(data, "displayBreakoutMaterial"); const editorialItemKind = mediaAttributes.attributeAsString(data, "kind"); const relatedCollection = mediaRelationship.relationshipCollection(data, "card-contents"); const tagline = content.editorialNotesFromData(objectGraph, data, "tagline"); const canPresentHeroModuleStyle = allowHeroModuleStylePresentation(objectGraph) && (tagline === null || tagline === void 0 ? void 0 : tagline.length) > 0; let relatedApp = mediaRelationship.relationshipData(objectGraph, data, "primary-content"); if (serverData.isNullOrEmpty(relatedApp) && serverData.isDefinedNonNullNonEmpty(relatedCollection)) { relatedApp = relatedCollection[0]; } if (serverData.isDefinedNonNull(relatedApp) && editorialItemKind === "App") { return canPresentHeroModuleStyle ? "singleModule" : "lockup"; } else if (serverData.isDefinedNonNullNonEmpty(relatedCollection) && editorialItemKind === "Collection") { return canPresentHeroModuleStyle ? "collectionModule" : "collectionLockup"; } else if (displayMaterial) { return "materialText"; } else { return objectGraph.client.isTV ? "materialText" : "text"; } } export function heroCarouselItemTitleFromData(objectGraph, data) { const overlayType = overlayTypeFromData(objectGraph, data); const primaryContent = mediaRelationship.relationshipData(objectGraph, data, "primary-content"); switch (overlayType) { case "lockup": case "singleModule": return mediaAttributes.attributeAsString(primaryContent, "name"); case "materialText": case "text": case "collectionLockup": case "collectionModule": return (content.editorialNotesFromData(objectGraph, data, "name") || contentAttributes.contentAttributeAsString(objectGraph, primaryContent, "name")); default: return null; } } export function overlayLockupFromData(objectGraph, data, requirements) { let relatedApp = mediaRelationship.relationshipData(objectGraph, data, "primary-content"); const relatedCollection = mediaRelationship.relationshipCollection(data, "card-contents"); if (serverData.isNullOrEmpty(relatedApp) && serverData.isDefinedNonNullNonEmpty(relatedCollection)) { relatedApp = relatedCollection[0]; } if (serverData.isNullOrEmpty(relatedApp)) { return null; } // Create the lockup const lockupOptions = { metricsOptions: { pageInformation: requirements.metricsPageInformation, locationTracker: requirements.metricsLocationTracker, recoMetricsData: mediaDataStructure.metricsFromMediaApiObject(data), }, artworkUseCase: requirements.lockupArtworkUseCase, offerStyle: "transparent", offerEnvironment: "dark", canDisplayArcadeOfferButton: requirements.canDisplayArcadeOfferButton, shouldHideArcadeHeader: objectGraph.featureFlags.isEnabled("hide_arcade_header_on_arcade_tab"), isContainedInPreorderExclusiveShelf: requirements.isContainedInPreorderExclusiveShelf, }; const lockup = lockups.lockupFromData(objectGraph, relatedApp, lockupOptions); const primaryContent = content.primaryContentForData(objectGraph, data); const editorialTagline = content.editorialNotesFromData(objectGraph, data, "short") || contentAttributes.contentAttributeAsString(objectGraph, primaryContent, "tagline"); if ((editorialTagline === null || editorialTagline === void 0 ? void 0 : editorialTagline.length) > 0) { lockup.subtitle = editorialTagline; } return lockup; } export function overlayCollectionIconsFromData(objectGraph, data) { const relatedCollection = mediaRelationship.relationshipCollection(data, "card-contents"); if (serverData.isNullOrEmpty(relatedCollection)) { return null; } const icons = []; for (const item of relatedCollection) { const icon = content.iconFromData(objectGraph, item, { useCase: 1 /* content.ArtworkUseCase.LockupIconSmall */, withJoeColorPlaceholder: true, }); if (serverData.isDefinedNonNullNonEmpty(icon)) { icons.push(icon); } } return serverData.isDefinedNonNullNonEmpty(icons) ? icons : null; } export function overlayButtonTitleFromData(objectGraph, data) { if (objectGraph.client.deviceType !== "tv") { return null; } const overlayType = overlayTypeFromData(objectGraph, data); switch (overlayType) { case "lockup": return objectGraph.loc.string("HERO_CAROUSEL_OVERLAY_BUTTON_TITLE_GAME"); case "materialText": case "text": let buttonTitle = objectGraph.loc.string("HERO_CAROUSEL_OVERLAY_BUTTON_TITLE_VIEW"); if (buttonTitle === "HERO_CAROUSEL_OVERLAY_BUTTON_TITLE_VIEW") { buttonTitle = objectGraph.loc.string("HERO_CAROUSEL_OVERLAY_BUTTON_TITLE_GAME"); } return buttonTitle; case "collectionLockup": return objectGraph.loc.string("HERO_CAROUSEL_OVERLAY_BUTTON_TITLE_COLLECTION"); default: return null; } } export function overlayIsOverDarkContent(objectGraph, data) { const heroVideoData = heroCommon.heroVideoFromData(objectGraph, data); const heroArtworkData = heroCommon.heroArtworkFromData(objectGraph, data); const backgroundColor = heroVideoData.backgroundColor || heroArtworkData.backgroundColor; if (!backgroundColor) { return true; } return color.isDarkColor(backgroundColor, 50); } export function overlayPlacementFromData(objectGraph, data) { if (objectGraph.client.isPhone) { return "center"; } if (objectGraph.client.isTV) { return "leading"; } const heroCarouselItemPlacementString = mediaAttributes.attributeAsString(data, "breakoutTextAlignment"); if (!serverData.isDefinedNonNullNonEmpty(heroCarouselItemPlacementString)) { return objectGraph.client.isMac ? "center" : "leading"; } switch (heroCarouselItemPlacementString.toLowerCase()) { case "left": return "leading"; case "center": return "center"; case "right": return "trailing"; default: return "leading"; } } /** * The text alignment to use for a particular detail position on large breakouts * @param data */ function overlayTextAlignmentFromData(objectGraph, data) { const placement = overlayPlacementFromData(objectGraph, data); const isTV = objectGraph.client.isTV; switch (placement) { case "leading": return "leading"; case "trailing": return "leading"; case "center": if (isTV) { return "leading"; } else { return objectGraph.client.isMac ? "center" : "leading"; } default: return "leading"; } } /** * Decides whether to account for the Hero 3.0 styles. * * @param objectGraph The object graph. */ function allowHeroModuleStylePresentation(objectGraph) { const isNotTV = !objectGraph.client.isTV; const isFeatureEnabledForCurrentUser = lottery.isFeatureEnabledForCurrentUser(objectGraph, objectGraph.bag.hero3RolloutRate); return isNotTV && isFeatureEnabledForCurrentUser; } //# sourceMappingURL=hero-carousel-overlay-common.js.map