This commit is contained in:
janisslsm committed 2026-11-01 12:12:55 +02:00
1 parent 1781d25a15
commit 732c0ad767
33051 files changed
+2591613 -3019689

No files matched your search

@@ -0,0 +1,210 @@
// Metro module 8651 (f8652).
import { isMessageComponentsV2 } from "../../records/MessageRecord";
import { ComponentType } from "../../flow/Server";
import { getUnfurledMediaItemType, messageAttachmentToMediaItem, embedMediaToMediaItem } from "../media/MediaTypes";
import { isImageContentType, isVideoContentType } from "../messages/MediaFormatTesters";
import maybeCreateMessageRecordFromSnapshot from "../forwarding/maybeCreateMessageRecordFromSnapshot";
import { createMessageRecord } from "../messages/MessageRecordUtils";
import { formatExpirationLabel } from "../polls/chat/useFormattedExpirationLabel";
import { intl, t } from "../../intl/index.native";
import URLUtils from "../../utils/URLUtils";
let c5628_4 = /^#{1,3}\s+(.+)$/;
let c5628_5 = /^https?:\/\/\S+$/;
export function toAnnouncementMessages(a0) {
return a0.map((item) => {
let r185, body2, content2, media, message;
L16: {
message = maybeCreateMessageRecordFromSnapshot(createMessageRecord(item));
content2 = message.content;
if (isMessageComponentsV2(message)) {
body2 = message.components.filter((component) => component.type === ComponentType.TEXT_DISPLAY).map((item) => item.content).join("\n");
} else {
const content = message.content;
if (content.length !== 0) {
const r41 = c5628_5.test(content.trim());
body2 = content;
if (!r41) {
break L16;
}
}
const r44 = message.embeds[0];
const r3 = r44 == null;
let r45 = null;
if (!r3) {
const r17 = [];
if (r44.rawTitle != null) {
r17.push(`# ${r44.rawTitle}`);
}
if (r44.rawDescription != null) {
r17.push(r44.rawDescription);
}
r45 = r17.length > 0 ? r17.join("\n") : null;
}
if (r45 == null) {
r45 = content;
}
body2 = r45;
}
}
L40: {
if (isMessageComponentsV2(message)) {
const r73 = message.components.find((component) => component.type === ComponentType.MEDIA_GALLERY);
const r76 = r73 == null ? void 0 : r73.items[0]?.media;
if (r76 != null) {
const unfurledMediaItemType = getUnfurledMediaItemType(r76);
if (unfurledMediaItemType !== "INVALID") {
media = {
...r76,
type: unfurledMediaItemType,
sourceMetadata: {
message
}
};
break L40;
}
}
}
const r88 = message.attachments.find((attachment) => isImageContentType(attachment.content_type));
if (r88 != null) {
media = messageAttachmentToMediaItem(r88, message);
} else {
const r93 = message.attachments.find((attachment) => isVideoContentType(attachment.content_type));
if (r93 != null) {
media = messageAttachmentToMediaItem(r93, message);
} else {
let c26253_0, c26253_1, c26253_2;
const r97 = message.embeds.find((embed) => embed.video != null && embed.thumbnail != null);
c26253_0 = r97;
if (r97?.thumbnail != null) {
media = embedMediaToMediaItem(r97.thumbnail, {
message,
identifier: {
type: "embed",
embedIndex: message.embeds.findIndex((embed) => embed === c26253_0)
}
}, "IMAGE");
} else {
const r103 = message.embeds.find((embed) => embed.image != null);
c26253_1 = r103;
if (r103?.image != null) {
media = embedMediaToMediaItem(r103.image, {
message,
identifier: {
type: "embed",
embedIndex: message.embeds.findIndex((embed) => embed === c26253_1)
}
}, "IMAGE");
} else {
const r108 = message.embeds.find((embed) => embed.thumbnail != null);
c26253_2 = r108;
media = r108?.thumbnail != null ? embedMediaToMediaItem(r108.thumbnail, {
message,
identifier: {
type: "embed",
embedIndex: message.embeds.findIndex((embed) => embed === c26253_2)
}
}, "IMAGE") : void 0;
}
}
}
}
}
const r151 = body2.indexOf("\n");
const r153 = r151 === -1;
const r159 = (r153 ? body2 : body2.slice(0, r151)).match(c5628_4);
const r161 = r159 != null ? {
title: r159[1].trim(),
body: r153 ? "" : body2.slice(r151 + 1).trimStart()
} : {
body: body2
};
const { title, body } = r161;
const reactions = item.reactions;
let reactionCount = reactions == null ? void 0 : reactions.reduce((acc, reaction) => acc + reaction.count, 0);
if (reactionCount == null) {
reactionCount = 0;
}
let embedSource = void 0;
if (body2 !== content2) {
const isMessageComponentsV22 = isMessageComponentsV2(message);
embedSource = void 0;
if (!isMessageComponentsV22) {
L80: {
const r183 = message.embeds[0];
const r184 = r183 != null;
r185 = void 0;
if (r184) {
const name = r183.author?.name;
let authorIconUrl = r183.author?.iconProxyURL;
if (authorIconUrl == null) {
authorIconUrl = r183.author?.iconURL;
}
let providerName = r183.footer?.text;
if (providerName == null) {
providerName = r183.provider?.name;
}
let providerIconUrl = r183.footer?.iconProxyURL;
if (providerIconUrl == null) {
providerIconUrl = r183.footer?.iconURL;
}
const url = r183.url;
let color = r183.color;
if (color == null) {
color = void 0;
}
if (name == null && providerName == null) {
const r209 = url != null;
r185 = void 0;
if (!r209) {
break L80;
}
}
r185 = {
authorName: name,
authorIconUrl,
providerName,
providerIconUrl,
url,
color
};
}
}
embedSource = r185;
}
}
return {
id: message.id,
media,
title,
body,
content: body2,
timestamp: item.timestamp,
reactionCount,
embedSource,
poll: message.poll
};
});
}
export function getPollExpiryLabel(a0) {
let r10 = formatExpirationLabel(a0.expiry);
if (r10 == null) {
r10 = intl.string(t["e+J3JZ"]);
}
return r10;
}
export function getPosterUrl(a0, a1, a2) {
const r13 = URLUtils.toURLSafe(a0);
const r1 = r13 == null;
let r15 = null;
if (!r1) {
r13.searchParams.append("format", "webp");
if (a1 != null) {
r13.searchParams.append("width", a1.toString());
}
if (a2 != null) {
r13.searchParams.append("height", a2.toString());
}
r15 = r13.toString();
}
return r15;
}
@@ -0,0 +1,41 @@
// Metro module 8480 (f8481).
import Module38 from "../../_bundle/Module38";
import ActionSheetActionCreators from "../action_sheet/native/ActionSheetActionCreators";
import Dispatcher from "../../Dispatcher";
const r13 = {
openGameProfileModal: function openGameProfileModal({ gameId, gameProfileModalChecks, source, sourceUserId, stackingBehavior }) {
Module38(gameProfileModalChecks.shouldOpenGameProfile, "Passed a false value for [gameProfileModalChecks]. Are you using the useShouldOpenGameProfile hook correctly?");
Module38(gameProfileModalChecks.gameId === gameId, "Passed an unexpected [gameId]. Are you passing a different one than you passed to useShouldOpenGameProfileModal?");
ActionSheetActionCreators.openLazy(import("./native/components/GameProfileScreen"), `game-profile-${gameId}`, {
gameId,
source,
sourceUserId
}, stackingBehavior);
},
returnToGameProfile: function returnToGameProfile({ gameId, source, initialScrollOffset }) {
Dispatcher.dispatch({
type: "GAME_PROFILE_CLEAR_PENDING_RETURN",
gameId
});
ActionSheetActionCreators.openLazy(import("./native/components/GameProfileScreen"), `game-profile-${gameId}`, {
gameId,
source,
initialScrollOffset
});
},
setGameProfilePendingReturn: function setGameProfilePendingReturn(a0) {
Dispatcher.dispatch({
type: "GAME_PROFILE_SET_PENDING_RETURN",
gameId: a0.gameId,
channelId: a0.channelId,
initialScrollOffset: a0.initialScrollOffset
});
},
clearGameProfilePendingReturn: function clearGameProfilePendingReturn(a0) {
Dispatcher.dispatch({
type: "GAME_PROFILE_CLEAR_PENDING_RETURN",
gameId: a0
});
}
};
export default r13;
@@ -0,0 +1,211 @@
// Metro module 8486 (f8487).
import ContentInventoryStore from "../content_inventory/ContentInventoryStore";
import { AnalyticEvents, GuildFeatures } from "../../Constants";
import { ContentInventoryFeedKey } from "../content_inventory/ContentInventoryConstants";
import { v4 } from "../../_bundle/Module514";
import AnalyticsUtils from "../../utils/AnalyticsUtils";
const r22 = {
CopyLink: 0,
0: "CopyLink"
};
const r24 = {
FollowGame: 0,
0: "FollowGame",
UnfollowGame: 1,
1: "UnfollowGame",
ClickMessageUser: 2,
2: "ClickMessageUser",
SendMessageUser: 3,
3: "SendMessageUser",
JoinVC: 4,
4: "JoinVC",
WatchStream: 5,
5: "WatchStream",
ClickSimilarGame: 6,
6: "ClickSimilarGame",
WebsiteLink: 7,
7: "WebsiteLink",
XLink: 8,
8: "XLink",
YouTubeLink: 9,
9: "YouTubeLink",
ShowMore: 10,
10: "ShowMore",
ShowLess: 11,
11: "ShowLess",
JoinServer: 12,
12: "JoinServer",
ClickImage: 13,
13: "ClickImage",
GameShop: 14,
14: "GameShop",
LinkAccount: 15,
15: "LinkAccount",
ClaimGame: 16,
16: "ClaimGame",
FacebookLink: 17,
17: "FacebookLink",
InstagramLink: 18,
18: "InstagramLink",
BlueskyLink: 19,
19: "BlueskyLink",
RedditLink: 20,
20: "RedditLink",
TwitchLink: 21,
21: "TwitchLink",
SteamStoreLink: 22,
22: "SteamStoreLink",
EpicStoreLink: 23,
23: "EpicStoreLink",
RobloxStoreLink: 24,
24: "RobloxStoreLink",
BattlenetStoreLink: 25,
25: "BattlenetStoreLink",
RiotStoreLink: 26,
26: "RiotStoreLink",
MinecraftStoreLink: 27,
27: "MinecraftStoreLink",
DiscordCollectiblesShop: 28,
28: "DiscordCollectiblesShop",
DiscordCollectiblesShopItem: 29,
29: "DiscordCollectiblesShopItem",
GameShopItem: 30,
30: "GameShopItem",
SteamReviews: 31,
31: "SteamReviews",
OpenCriticReviews: 32,
32: "OpenCriticReviews",
Announcements: 33,
33: "Announcements",
AnnouncementsItem: 34,
34: "AnnouncementsItem",
CloudPlay: 35,
35: "CloudPlay",
ClickTrailer: 36,
36: "ClickTrailer",
Feedback: 37,
37: "Feedback",
XboxGamePassStoreLink: 38,
38: "XboxGamePassStoreLink",
CopyLink: 39,
39: "CopyLink"
};
const r103 = {
ActivityCard: "activity_card",
ActivityCardContextMenu: "activity_card_context_menu",
UserProfile: "user_profile",
UserProfileApplicationWidget: "user_profile_application_widget",
UserProfileCardContextMenu: "user_profile_card_context_menu",
SimilarGames: "similar_games",
DevTools: "dev_tools",
Embed: "embed",
GameProfileEmbed: "game_profile_embed",
RtcPanel: "rtc_panel",
FriendsActivityFeed: "friends_activity_feed",
MiniGameProfile: "mini_game_profile",
GameMention: "game_mention",
GameSheet: "game_sheet",
QuestBar: "quest_bar",
QuestHome: "quest_home_desktop",
QuestInGameModal: "quest_in_game_modal",
QuestActivityPanel: "quest_activity_panel",
QuestEmbed: "quest_embed",
QuestLiveStream: "quest_live_stream",
ClipEmbed: "clip_embed",
ClipsReminder: "clips_reminder",
AnnouncementChannelReturn: "announcement_channel_return",
CallTile: "call_tile",
InAppBrowserReturn: "in_app_browser_return",
Deeplink: "deeplink",
DmHeaderActivity: "dm_header_activity",
QuickSwitcher: "quick_switcher",
GuildProfileGames: "guild_profile_games",
GameInvitesChannel: "game_invites_channel"
};
const r134 = {
FullProfile: "full_profile",
MiniProfile: "mini_profile"
};
export { r22 as GameProfileEmbedAction };
export { r24 as GameProfileTrackActionActions };
export { r103 as GameProfileSources };
export { r134 as GameProfileTypes };
export function getGuildIdAndVerifiedFromInvite(a0) {
let guildId = a0 == null ? void 0 : a0.guild?.id;
if (guildId == null) {
guildId = null;
}
const r10 = a0 == null;
let isVerified = void 0;
if (!r10) {
const guild = a0.guild;
isVerified = guild == null ? void 0 : guild.features.includes(GuildFeatures.VERIFIED);
}
if (isVerified == null) {
isVerified = false;
}
return {
guildId,
isVerified
};
}
export function generateViewId() {
return v4();
}
export function trackGameProfileOpen({ viewId, source, gameName, gameId, authorId, profileType }) {
AnalyticsUtils.track(AnalyticEvents.GAME_PROFILE_OPEN, {
view_id: viewId,
source,
game_name: gameName,
application_id: gameId,
author_id: authorId,
request_id: ContentInventoryStore.getFeedRequestId(ContentInventoryFeedKey.GLOBAL_FEED),
profile_type: profileType
});
return viewId;
}
export function trackGameProfileClose({ viewId, gameName, gameId, playedFriendIds, playedFriendsData, similarGames, guildId, isVerified }) {
AnalyticsUtils.track(AnalyticEvents.GAME_PROFILE_CLOSE, {
view_id: viewId,
game_name: gameName,
application_id: gameId,
played_friend_ids: playedFriendIds,
played_friends_data: playedFriendsData,
similar_games: similarGames,
request_id: ContentInventoryStore.getFeedRequestId(ContentInventoryFeedKey.GLOBAL_FEED),
official_guild_id: isVerified ? guildId : void 0,
guild_id: guildId
});
}
export function trackGameProfileAction(a0) {
const { gameName, gameId, action, recipientUserId, similarGameId, viewId, guildId } = a0;
AnalyticsUtils.track(AnalyticEvents.GAME_PROFILE_ACTION, {
game_name: gameName,
application_id: gameId,
action,
recipient_user_id: recipientUserId,
similar_game_id: similarGameId,
view_id: viewId,
official_guild_id: a0.isVerified ? guildId : void 0,
guild_id: guildId,
source: a0.source
});
}
export function trackGameProfileEmbedAction(a0) {
AnalyticsUtils.track(AnalyticEvents.GAME_PROFILE_EMBED_ACTION, {
game_name: a0.gameName,
application_id: a0.gameId,
action: a0.action
});
}
export function trackGameProfileFeedback(a0) {
const { viewId, applicationId } = a0;
return AnalyticsUtils.track(AnalyticEvents.GAME_PROFILE_FEEDBACK, {
view_id: viewId,
application_id: applicationId,
suggested_game_name: a0.suggestedGameName,
suggested_game_application_id: a0.suggestedGameApplicationId,
feedback: a0.feedback,
submitted: a0.submitted
});
}
@@ -0,0 +1,185 @@
// Metro module 8656 (f8657).
import LocaleStore from "../user_settings/LocaleStore";
import GameProfileStore from "./GameProfileStore";
import { Endpoints } from "../../Constants";
import { SIMILAR_GAMES_BLOCKED_GAME_IDS } from "../../_bundle/Module8657";
import Dispatcher from "../../Dispatcher";
import { httpGetWithCountryCodeQuery } from "../../utils/StoreUtils";
import { HTTP } from "../../_bundle/sendRequest";
import { createFetchStore } from "../../_bundle/Module589";
import Backoff from "../../_bundle/Backoff";
import Durations from "../../utils/Durations";
import { toAnnouncementMessages } from "./AnnouncementMessageUtils";
function $mk115326($env) {
return (a0) => a0 !== $env[0] && !SIMILAR_GAMES_BLOCKED_GAME_IDS.has(a0);
}
let env5633 = {};
env5633[9] = function _fetchSimilarGames() {
const r8 = async (c26255_0) => {
let env29959;
const r11 = env5633;
let c26255_3 = r11;
const r23 = env29959 = {
$parent: r11
};
let c26255_2 = r23;
env29959[0] = c26255_0;
env29959[1] = void 0;
const similar_games2 = (await HTTP.get({
url: Endpoints.SIMILAR_GAMES(c26255_0),
rejectWithError: true
})).body.similar_games;
let similar_games = similar_games2;
if (similar_games2 == null) {
similar_games = [];
}
env29959[1] = similar_games.filter($mk115326(c26255_2));
Dispatcher.dispatch({
type: "GAME_PROFILE_GET_SIMILAR_GAMES_SUCCESS",
gameId: env29959[0],
games: env29959[1]
});
};
env5633[9] = r8;
return r8.apply(this, arguments);
};
const fetchStore = createFetchStore(GameProfileStore, {
getQueryId: (a0, a1) => a1 ? `similar-games:${a0}` : null,
get: (a0) => {
let r5 = GameProfileStore.getSimilarGames(a0);
if (r5 == null) {
r5 = null;
}
return r5;
},
load: (a0) => (function fetchSimilarGames() {
return env5633[9].apply(this, arguments);
})(a0),
retryConfig: {
backoff: () => new Backoff(5 * Durations.Millis.SECOND, 5 * Durations.Millis.MINUTE)
},
failureStaleAfter: Durations.Seconds.MINUTE
});
export async function getShopCollection(collectionId) {
let c26254_1, c26254_2, c26254_3;
let c26254_4 = 0;
const r11 = env5633;
L10: {
try {
let env29958;
c26254_2 = r11;
const r27 = env29958 = {};
c26254_1 = r27;
env29958[0] = collectionId;
env29958[1] = void 0;
Dispatcher.dispatch({
type: "GAME_PROFILE_GET_SHOP_COLLECTION_START",
collectionId
});
c26254_4 = 1;
env29958[1] = (await httpGetWithCountryCodeQuery({
url: Endpoints.STOREFRONT_COLLECTION_WITH_PRODUCTS(collectionId),
query: {
locale: LocaleStore.locale
},
rejectWithError: false,
retries: 2
})).body.products.flatMap((product) => product.sku_ids);
Dispatcher.dispatch({
type: "GAME_PROFILE_GET_SHOP_COLLECTION_SUCCESS",
collectionId: env29958[0],
skuIds: env29958[1]
});
c26254_4 = 0;
} catch ($e) {
const r25 = $e;
let r8 = r25;
c26254_3 = r25;
if (c26254_4 !== 0) {
while (true) {
try {
c26254_4 = 0;
Dispatcher.dispatch({
type: "GAME_PROFILE_GET_SHOP_COLLECTION_ERROR",
collectionId: env29958[0]
});
break L10;
} catch (r79) {
r8 = r79;
c26254_3 = r79;
if (c26254_4 === 0) {
break;
}
}
}
}
throw r8;
}
}
}
export { fetchStore as useSimilarGameIds };
export async function getGameAnnouncements(gameId, c26256_1) {
let channel_id, guild_id;
let c26256_7 = 0;
let c29960_0, c29960_1;
L18: {
try {
c29960_0 = gameId;
c29960_1 = void 0;
Dispatcher.dispatch({
type: "GAME_PROFILE_GET_ANNOUNCEMENTS_START",
gameId
});
c26256_7 = 1;
const limit = c26256_1?.limit;
const query = {};
if (limit != null) {
query.limit = c26256_1.limit;
}
c29960_1 = (await HTTP.get({
url: Endpoints.GAME_ANNOUNCEMENTS(gameId),
query,
rejectWithError: false
})).body;
const r73 = {
type: "GAME_PROFILE_GET_ANNOUNCEMENTS_SUCCESS",
gameId: c29960_0,
messages: toAnnouncementMessages(c29960_1.messages),
channelId: null,
guildId: null
};
channel_id = c29960_1.channel_id;
if (channel_id == null) {
channel_id = void 0;
}
r73.channelId = channel_id;
guild_id = c29960_1.guild_id;
if (guild_id == null) {
guild_id = void 0;
}
r73.guildId = guild_id;
Dispatcher.dispatch(r73);
c26256_7 = 0;
} catch ($e) {
let r8 = $e;
if (c26256_7 !== 0) {
while (true) {
try {
c26256_7 = 0;
Dispatcher.dispatch({
type: "GAME_PROFILE_GET_ANNOUNCEMENTS_ERROR",
gameId: c29960_0
});
break L18;
} catch ($e) {
r8 = $e;
if (c26256_7 === 0) {
break;
}
}
}
}
throw r8;
}
}
}
@@ -0,0 +1,54 @@
// Metro module 8523 (f8524).
import { SteamReviewScoreDescription } from "../game_detection/GameDetectionTypes";
import { intl, t } from "../../intl/index.native";
export function getSteamReviewScoreDescriptionColor(a0) {
if (SteamReviewScoreDescription.NO_USER_REVIEWS === a0) {
return "text-subtle";
}
if (SteamReviewScoreDescription.OVERWHELMINGLY_POSITIVE !== a0 && SteamReviewScoreDescription.VERY_POSITIVE !== a0 && SteamReviewScoreDescription.POSITIVE !== a0 && SteamReviewScoreDescription.MOSTLY_POSITIVE !== a0) {
if (SteamReviewScoreDescription.MIXED === a0) {
return "steam-review-text-mixed";
}
if (SteamReviewScoreDescription.MOSTLY_NEGATIVE !== a0 && SteamReviewScoreDescription.NEGATIVE !== a0 && SteamReviewScoreDescription.VERY_NEGATIVE !== a0 && SteamReviewScoreDescription.OVERWHELMINGLY_NEGATIVE !== a0) {
return "text-subtle";
}
return "steam-review-text-negative";
}
return "steam-review-text-positive";
}
export function getSteamReviewScoreDescriptionIntl(a0) {
if (SteamReviewScoreDescription.NO_USER_REVIEWS === a0) {
return intl.string(t.CLMt8J);
}
if (SteamReviewScoreDescription.OVERWHELMINGLY_POSITIVE === a0) {
return intl.string(t["75sx1S"]);
}
if (SteamReviewScoreDescription.VERY_POSITIVE === a0) {
return intl.string(t["EkOVg+"]);
}
if (SteamReviewScoreDescription.POSITIVE === a0) {
return intl.string(t.ZUkFtr);
}
if (SteamReviewScoreDescription.MOSTLY_POSITIVE === a0) {
return intl.string(t.M7Z09a);
}
if (SteamReviewScoreDescription.MIXED === a0) {
return intl.string(t.c8yuHR);
}
if (SteamReviewScoreDescription.MOSTLY_NEGATIVE === a0) {
return intl.string(t.H0MSjG);
}
if (SteamReviewScoreDescription.NEGATIVE === a0) {
return intl.string(t.vpLrgz);
}
if (SteamReviewScoreDescription.VERY_NEGATIVE === a0) {
return intl.string(t["5spYuX"]);
}
if (SteamReviewScoreDescription.OVERWHELMINGLY_NEGATIVE === a0) {
return intl.string(t.A8uk5J);
}
return null;
}
export function canShowLocalizedSteamReview(a0) {
return a0 != null && a0.localizedRating != null && a0.localizedRatingCount != null && a0.ratingCount != null && a0.localizedRatingCount >= 200 && a0.ratingCount >= 2000;
}
+111
View File
@@ -0,0 +1,111 @@
// Metro module 8482 (f8483).
import Module589 from "../../_bundle/Module589";
import Dispatcher from "../../Dispatcher";
let c5432_0 = {};
let c5432_1 = {};
let c5432_2 = {};
let c5432_3 = {};
let c5432_4 = {};
let c5432_5 = {};
let c5432_6 = {};
let c5432_7 = null;
class GameProfileStore extends Module589.Store {
static displayName = "GameProfileStore";
getSimilarGames(a0) {
return c5432_0[a0];
}
getShopCollectionSkuIds(a0) {
return c5432_1[a0];
}
hasShopCollectionBeenFetched(a0) {
let r4 = c5432_2[a0];
if (r4 == null) {
r4 = false;
}
return r4;
}
isShopCollectionFetching(a0) {
let r4 = c5432_3[a0];
if (r4 == null) {
r4 = false;
}
return r4;
}
getAnnouncements(a0) {
return c5432_4[a0];
}
hasAnnouncementsBeenFetched(a0) {
let r4 = c5432_5[a0];
if (r4 == null) {
r4 = false;
}
return r4;
}
isAnnouncementsFetching(a0) {
let r4 = c5432_6[a0];
if (r4 == null) {
r4 = false;
}
return r4;
}
getPendingReturn() {
return c5432_7;
}
}
const gameProfileStore = new GameProfileStore(Dispatcher, {
GAME_PROFILE_GET_SIMILAR_GAMES_SUCCESS: function handleGetSimilarGamesSuccess(a0) {
c5432_0[a0.gameId] = a0.games;
},
GAME_PROFILE_GET_SHOP_COLLECTION_START: function handleGetShopCollectionStart(a0) {
c5432_3[a0.collectionId] = true;
},
GAME_PROFILE_GET_SHOP_COLLECTION_SUCCESS: function handleGetShopCollectionSuccess(a0) {
const collectionId = a0.collectionId;
c5432_1[collectionId] = a0.skuIds;
c5432_2[collectionId] = true;
c5432_3[collectionId] = false;
},
GAME_PROFILE_GET_SHOP_COLLECTION_ERROR: function handleGetShopCollectionError({ collectionId }) {
c5432_2[collectionId] = true;
c5432_3[collectionId] = false;
},
GAME_PROFILE_GET_ANNOUNCEMENTS_START: function handleGetAnnouncementsStart(a0) {
c5432_6[a0.gameId] = true;
},
GAME_PROFILE_GET_ANNOUNCEMENTS_SUCCESS: function handleGetAnnouncementsSuccess(a0) {
const gameId = a0.gameId;
c5432_4[gameId] = {
messages: a0.messages,
channelId: a0.channelId,
guildId: a0.guildId
};
c5432_5[gameId] = true;
c5432_6[gameId] = false;
},
GAME_PROFILE_GET_ANNOUNCEMENTS_ERROR: function handleGetAnnouncementsError({ gameId }) {
c5432_5[gameId] = true;
c5432_6[gameId] = false;
},
GAME_PROFILE_SET_PENDING_RETURN: function handleSetPendingReturn({ gameId, channelId, initialScrollOffset }) {
if (c5432_7?.gameId === gameId) {
if (c5432_7?.channelId === channelId) {
if (c5432_7?.initialScrollOffset === initialScrollOffset) {
return false;
}
}
}
c5432_7 = {
gameId,
channelId,
initialScrollOffset
};
},
GAME_PROFILE_CLEAR_PENDING_RETURN: function handleClearPendingReturn({ gameId }) {
if (c5432_7 != null && c5432_7.gameId === gameId) {
c5432_7 = null;
return void 0;
}
return false;
}
});
export default gameProfileStore;
@@ -0,0 +1,40 @@
// Metro module 8512 (f8513).
import { createApexExperiment } from "../experiments/apex/index";
const defaultConfig = {
enabled: false,
dense: false
};
const apexExperiment = createApexExperiment({
kind: "user",
name: "2026-06-similar-games-desktop",
defaultConfig,
variations: {
0: defaultConfig,
1: {
enabled: true,
dense: true
},
2: {
enabled: true,
dense: false
}
}
});
const apexExperiment2 = createApexExperiment({
kind: "user",
name: "2026-06-similar-games-mobile",
defaultConfig,
variations: {
0: defaultConfig,
1: {
enabled: true,
dense: true
},
2: {
enabled: true,
dense: false
}
}
});
export { apexExperiment as GameProfileSimilarGamesDesktopExperiment };
export { apexExperiment2 as GameProfileSimilarGamesMobileExperiment };
@@ -0,0 +1,34 @@
// Metro module 8655 (f8656).
import { useEffect } from "react";
import GameProfileStore from "../GameProfileStore";
import { useStateFromStoresObject } from "../../../_bundle/Module589";
import { getGameAnnouncements } from "../GameProfileHttpUtils";
export default function useGameAnnouncements(a0, a1) {
let hasFetched;
const limit = a1;
const stateFromStoresObject = useStateFromStoresObject([GameProfileStore], () => ({
data: a0 != null ? GameProfileStore.getAnnouncements(a0) : void 0,
hasFetched: a0 != null && GameProfileStore.hasAnnouncementsBeenFetched(a0),
isFetching: a0 != null && GameProfileStore.isAnnouncementsFetching(a0)
}));
const data = stateFromStoresObject.data;
hasFetched = stateFromStoresObject.hasFetched;
const isFetching = stateFromStoresObject.isFetching;
useEffect(() => {
if (!(a0 == null || hasFetched || GameProfileStore.isAnnouncementsFetching(a0))) {
getGameAnnouncements(a0, {
limit
});
}
}, [a0, hasFetched, a1]);
let messages = data?.messages;
if (messages == null) {
messages = [];
}
return {
messages,
channelId: data?.channelId,
guildId: data?.guildId,
loading: isFetching
};
};
@@ -0,0 +1,11 @@
// Metro module 8487 (f8488).
import UserStore from "../../../stores/UserStore";
import { isAgeRestrictedContentClassification } from "../../content_classification/utils";
import { useStateFromStores } from "../../../_bundle/Module589";
export default function useGameProfileObscured(a0) {
const stateFromStores = useStateFromStores([UserStore], () => UserStore.getCurrentUser()?.nsfwAllowed);
return a0 != null && stateFromStores === false && isAgeRestrictedContentClassification(a0.contentClassification);
};
export function isGameProfileObscured(a0, a1) {
return a0 != null && a1 === false && isAgeRestrictedContentClassification(a0.contentClassification);
}
@@ -0,0 +1,41 @@
// Metro module 8524 (f8525).
import { OpenCriticTier } from "../../../_bundle/Module8525";
import { intl, t } from "../../../intl/index.native";
import Module8526 from "../../../_bundle/Module8526";
import Module8527 from "../../../_bundle/Module8527";
import Module8528 from "../../../_bundle/Module8528";
import Module8529 from "../../../_bundle/Module8529";
export function getOpenCriticTierText(a0) {
if (OpenCriticTier.MIGHTY === a0) {
return intl.string(t.aZej2g);
}
if (OpenCriticTier.STRONG === a0) {
return intl.string(t.MLxnSg);
}
if (OpenCriticTier.FAIR === a0) {
return intl.string(t["3f19KA"]);
}
if (OpenCriticTier.WEAK === a0) {
return intl.string(t.jtVgSh);
}
}
export function getOpenCriticTierImage(a0) {
if (OpenCriticTier.MIGHTY === a0) {
return Module8526;
}
if (OpenCriticTier.STRONG === a0) {
return Module8527;
}
if (OpenCriticTier.FAIR === a0) {
return Module8528;
}
if (OpenCriticTier.WEAK === a0) {
return Module8529;
}
}
export function getOpenCriticCircleRatingColor(a0) {
return {
foregroundColor: OpenCriticTier.MIGHTY !== a0 ? OpenCriticTier.STRONG !== a0 ? OpenCriticTier.FAIR !== a0 ? OpenCriticTier.WEAK === a0 ? "#80b06a" : "" : "#4aa1ce" : "#9e00b4" : "#fc430a",
backgroundColor: "#2e2e2e"
};
}
@@ -0,0 +1,23 @@
// Metro module 11920 (f11921).
import { useEffect } from "react";
import GameProfileStore from "../GameProfileStore";
import { useStateFromStoresObject } from "../../../_bundle/Module589";
import { getShopCollection } from "../GameProfileHttpUtils";
export function useGameProfileShopCollection(a0) {
let hasFetched;
const stateFromStoresObject = useStateFromStoresObject([GameProfileStore], () => ({
hasFetched: a0 != null && GameProfileStore.hasShopCollectionBeenFetched(a0),
skuIds: a0 != null ? GameProfileStore.getShopCollectionSkuIds(a0) : void 0
}));
hasFetched = stateFromStoresObject.hasFetched;
let skuIds = stateFromStoresObject.skuIds;
useEffect(() => {
if (!(a0 == null || hasFetched || GameProfileStore.isShopCollectionFetching(a0))) {
getShopCollection(a0);
}
}, [a0, hasFetched]);
if (skuIds == null) {
skuIds = [];
}
return skuIds;
}
@@ -0,0 +1,42 @@
// Metro module 8489 (f8490).
import { useMemo } from "react";
import { ThirdPartyGameApplicationWebsiteCategory } from "../../../_bundle/Module8490";
import { useSteamWebsiteUrl } from "./useSteamWebsiteUrl";
import useXboxGamePassStoreUrl from "./useXboxGamePassStoreUrl";
import { SteamReleaseStatus } from "../../../_bundle/Module8492";
let c5439_4 = new Set(["1402418703554842694", "356877880938070016"]);
let c5439_5 = [ThirdPartyGameApplicationWebsiteCategory.EPICGAMES, ThirdPartyGameApplicationWebsiteCategory.STEAM, ThirdPartyGameApplicationWebsiteCategory.ROBLOX, ThirdPartyGameApplicationWebsiteCategory.BATTLENET, ThirdPartyGameApplicationWebsiteCategory.RIOT, ThirdPartyGameApplicationWebsiteCategory.MINECRAFT];
export function useGameProfileStoreWebsites(a0) {
const id2 = a0?.id;
const steamWebsiteUrl = useSteamWebsiteUrl(id2);
const url = useXboxGamePassStoreUrl(a0);
const id = a0?.id;
const websites = a0?.websites;
const steamReleaseStatus = a0?.steamReleaseStatus;
return useMemo(() => {
if (!(websites == null && url == null) && id != null) {
let r6 = websites == null ? void 0 : websites.filter((website) => {
const r0 = website.category === ThirdPartyGameApplicationWebsiteCategory.EPICGAMES && !c5439_4.has(id);
return r0 ? !r0 : (website.category !== ThirdPartyGameApplicationWebsiteCategory.STEAM || steamReleaseStatus !== SteamReleaseStatus.RETIRED_ABANDONED) && c5439_5.includes(website.category);
});
if (r6 == null) {
r6 = [];
}
if (!(steamWebsiteUrl == null || steamReleaseStatus === SteamReleaseStatus.RETIRED_ABANDONED || r6.some((item) => item.category === ThirdPartyGameApplicationWebsiteCategory.STEAM))) {
r6.push({
category: ThirdPartyGameApplicationWebsiteCategory.STEAM,
url: steamWebsiteUrl
});
}
const r36 = r6.sort((a, b) => a.category !== ThirdPartyGameApplicationWebsiteCategory.STEAM ? b.category === ThirdPartyGameApplicationWebsiteCategory.STEAM ? 1 : 0 : -1);
if (url != null) {
r36.unshift({
category: "XBOX_GAME_PASS",
url
});
}
return r36;
}
return [];
}, [steamWebsiteUrl, websites, id, steamReleaseStatus, url]);
}
@@ -0,0 +1,227 @@
// Metro module 8483 (f8484).
import _slicedToArray from "../../../_bundle/_slicedToArray";
import _asyncToGenerator from "../../../_bundle/_asyncToGenerator";
import { useState, useCallback } from "react";
import GameUtils_native from "../../../utils/GameUtils.native";
import { XBOX_GAME_PASS_STORE_HOSTNAME, XBOX_GAME_PASS_PROTOCOL, buildXboxGamePassStoreDeepLinkUrl } from "../../activities/utils/distributorStoreUrls";
import openURL from "../../../lib/openURL";
import { HermesBuiltin, $createGenerator } from "../../../_hermes/prelude";
function $mk118098($env) {
return function openDeepLink(a0, c31977_0) {
let c31977_1 = setTimeout(() => c31977_0(true), 5000);
window.addEventListener("blur", () => clearTimeout(c31977_1), {
once: true
});
openURL(a0);
};
}
let c5433_6, c5433_7, c5433_8;
let env5433 = {};
env5433[9] = function _getDeepLinkUrl() {
const r8 = async (c26209_0) => {
let r67, r100, r145;
let c29954_0, c29954_1, c29954_2;
L20: {
L19: {
L28: {
L11: {
c29954_0 = c26209_0;
c29954_1 = void 0;
c29954_2 = void 0;
if (c26209_0.hostname === "store.steampowered.com") {
if (await GameUtils_native.isProtocolRegistered(c5433_6)) {
const r130 = c29954_0.pathname.match(c5433_7);
c29954_1 = r130 == null ? void 0 : r130[1];
if (c29954_1 != null) {
r145 = `${c5433_6}://store/${c29954_1}`;
break L28;
}
}
if (c29954_0.hostname !== XBOX_GAME_PASS_STORE_HOSTNAME) {
break L20;
}
r67 = await GameUtils_native.isProtocolRegistered(XBOX_GAME_PASS_PROTOCOL);
} else {
if (c29954_0.hostname !== XBOX_GAME_PASS_STORE_HOSTNAME) {
break L11;
}
r67 = await GameUtils_native.isProtocolRegistered(XBOX_GAME_PASS_PROTOCOL);
}
if (!r67) {
break L20;
}
const r82 = c29954_0.pathname.match(c5433_8);
c29954_2 = r82 == null ? void 0 : r82[1];
if (c29954_2 == null) {
break L20;
}
r100 = buildXboxGamePassStoreDeepLinkUrl(decodeURIComponent(c29954_2));
break L19;
}
return null;
}
return r145;
}
return r100;
}
return null;
};
env5433[9] = r8;
return r8.apply(this, arguments);
};
c5433_6 = "steam";
c5433_7 = /^\/app\/(\d+)(?:\/)?/;
c5433_8 = /^\/games\/store\/title\/([^/]+)/;
export default function useOpenExternalUrlFromGameProfile(a0) {
let env16612 = {
$parent: env5433
};
env16612[0] = a0;
const r11 = _slicedToArray(useState(false), 2);
const r12 = r11[0];
env16612[1] = r12;
env16612[2] = r11[1];
let c16613_0 = _asyncToGenerator(function(c29955_0) {
let c29955_1, c29955_2;
let c29955_4 = 0;
let c29955_5 = 0;
let c29955_3 = 0;
return $createGenerator(function(a0) {
let value2;
const r0 = c29955_5;
if (r0 === 2) {
c29955_5 = 3;
HermesBuiltin.throwTypeError("Generator functions may not be called on executing generators");
throw new Error("unreachable");
}
const value = arguments[1];
const r12 = void 0;
const r11 = env5433;
if (r0 === 3) {
if (a0 === 1) {
throw value;
}
if (a0 === 2) {
return {
value,
done: true
};
}
return {
value: void 0,
done: true
};
}
while (true) {
L28: {
L26: {
L24: {
L19: {
L16: {
try {
c29955_5 = 2;
const r24 = c29955_4;
if (r24 === 0) {
if (a0 === 1) {
c29955_5 = 3;
throw value;
}
if (a0 === 2) {
c29955_5 = 3;
break L28;
}
let env31470;
c29955_2 = r12;
const r69 = env31470 = {
$parent: r11
};
c29955_1 = r69;
env31470[0] = c29955_0;
env31470[1] = void 0;
env31470[2] = void 0;
if (env31470[0] != null) {
c29955_3 = 1;
const uRL = new URL(env31470[0]);
env31470[1] = uRL;
c29955_3 = 0;
value2 = (function getDeepLinkUrl() {
return env5433[9].apply(this, arguments);
})(uRL);
c29955_4 = 2;
c29955_5 = 1;
break L26;
}
} else {
if (r24 === 1) {
c29955_3 = 0;
c29955_5 = 3;
break L19;
}
if (a0 === 1) {
c29955_5 = 3;
throw value;
}
if (a0 === 2) {
c29955_5 = 3;
break L16;
}
env31470[2] = value;
if (env31470[2] != null && c29955_2.$parent[1]) {
env31470[2] = null;
}
const r30 = c29955_2;
env31470[1].searchParams.set("utm_source", "discord");
env31470[0] = env31470[1].toString();
if (r30.$parent[0] != null) {
(0, c29955_2.$parent[0])(env31470[0]);
} else if (env31470[2] != null) {
const r51 = c29955_2;
const r52 = env31470[2];
const r54 = r51.$parent[2];
$mk118098(env5433)(r52, r54);
} else {
openURL(env31470[0]);
}
}
c29955_5 = 3;
break L24;
} catch (r85) {
if (c29955_3 === 0) {
c29955_5 = 3;
throw r85;
}
c29955_4 = 1;
continue;
}
}
return {
value,
done: true
};
}
return {
value: void 0,
done: true
};
}
return {
value: void 0,
done: true
};
}
return {
value: value2,
done: false
};
}
return {
value,
done: true
};
}
});
});
return useCallback(function() {
return c16613_0.apply(this, arguments);
}, [a0, r12]);
};
@@ -0,0 +1,29 @@
// Metro module 8475 (f8476).
import useShouldOpenGameProfileModal from "./useShouldOpenGameProfileModal";
import GameProfileActionCreators_native from "../GameProfileActionCreators.native";
export default function useOpenGameProfileModal(a0) {
let c16608_0 = a0;
let r5 = arguments[1];
if (r5 === void 0) {
r5 = {};
}
const onOpened = r5.onOpened;
const gameProfileModalChecks = useShouldOpenGameProfileModal(a0);
const gameId = gameProfileModalChecks.gameId;
return gameProfileModalChecks.shouldOpenGameProfile ? gameId != null ? (a0) => {
if (a0 != null) {
a0.stopPropagation();
}
if (a0 != null) {
a0.preventDefault();
}
GameProfileActionCreators_native.openGameProfileModal({
...c16608_0,
gameId,
gameProfileModalChecks
});
if (onOpened != null) {
onOpened();
}
} : void 0 : void 0;
};
@@ -0,0 +1,45 @@
// Metro module 11522 (f11523).
import { useCallback, useEffect } from "react";
import GameStore from "../../games/GameStore";
import GameProfileStore from "../GameProfileStore";
import { AVATAR_SIZE } from "../../../Constants";
import { useStateFromStores } from "../../../_bundle/Module589";
import GameProfileActionCreators_native from "../GameProfileActionCreators.native";
import { GameProfileSources } from "../GameProfileAnalyticUtils";
export default function usePendingGameProfileReturn({ channelId }) {
let stateFromStores2;
stateFromStores2 = void 0;
const stateFromStores = useStateFromStores([GameProfileStore], () => {
const pendingReturn = GameProfileStore.getPendingReturn();
return pendingReturn == null ? null : pendingReturn.channelId === channelId ? pendingReturn : null;
});
const callback = useCallback(() => {
if (stateFromStores != null) {
GameProfileActionCreators_native.returnToGameProfile({
gameId: stateFromStores.gameId,
source: GameProfileSources.AnnouncementChannelReturn,
initialScrollOffset: stateFromStores.initialScrollOffset
});
}
}, [stateFromStores]);
stateFromStores2 = useStateFromStores([GameStore], () => stateFromStores?.gameId != null ? GameStore.getGame(stateFromStores.gameId) : null);
useEffect(() => {
if (stateFromStores2?.id != null) {
return () => GameProfileActionCreators_native.clearGameProfilePendingReturn(stateFromStores2.id);
}
}, [stateFromStores2?.id]);
const name = stateFromStores2?.name;
if (stateFromStores2 != null && name != null) {
let gameIconUrl = stateFromStores2 == null ? void 0 : stateFromStores2.getIconURL(AVATAR_SIZE);
if (gameIconUrl == null) {
gameIconUrl = void 0;
}
return {
gameId: stateFromStores2.id,
gameName: name,
gameIconUrl,
onReturnToGameProfile: callback
};
}
return null;
};
@@ -0,0 +1,33 @@
// Metro module 8478 (f8479).
import { useGetOrFetchApplication } from "../../applications/useGetOrFetchApplications";
import { isRobloxSubgameApplication, isRobloxSubgameGame } from "../../roblox_subgame_detection/RobloxSubgameUtils";
import useResolveGame from "../../games/hooks/useResolveGame";
import { ROBLOX_GAME_ID } from "../../roblox_subgame_detection/RobloxSubgameTypes";
import { useGame } from "../../games/hooks/useGame";
export default function useResolveGameForProfile(a0) {
const applicationId = a0.applicationId;
let gameId = a0.gameId;
const getOrFetchApplication = useGetOrFetchApplication(gameId == null ? applicationId : void 0);
if (getOrFetchApplication != null && isRobloxSubgameApplication(getOrFetchApplication)) {
gameId = ROBLOX_GAME_ID;
}
let r24 = useResolveGame({
applicationId,
gameId
});
const r26 = r24.gameRecord != null && isRobloxSubgameGame(r24.gameRecord);
const game = useGame(r26 ? ROBLOX_GAME_ID : void 0);
let data = game.data;
const isLoading = game.isLoading;
if (r26) {
if (data == null) {
data = null;
}
r24 = {
gameId: ROBLOX_GAME_ID,
gameRecord: data,
isLoading
};
}
return r24;
};
@@ -0,0 +1,108 @@
// Metro module 8476 (f8477).
import { useRef, useEffect } from "react";
import GameStore from "../../games/GameStore";
import { AnalyticEvents } from "../../../Constants";
import AnalyticsUtils from "../../../utils/AnalyticsUtils";
import { hasFlag } from "../../../_bundle/Module1384";
import { GameFlags } from "../../../_bundle/Module8477";
import * as _utils from "../../content_classification/utils";
import useResolveGameForProfile from "./useResolveGameForProfile";
import Module38 from "../../../_bundle/Module38";
let c5427_7 = {
NoMatch: "no match",
NSFW: "nsfw",
Disabled: "profile disabled"
};
export default function useShouldOpenGameProfileModal({ applicationId = "", gameId, source, trackEntryPointImpression = true }) {
let r44;
let c16609_1 = trackEntryPointImpression;
const ref = useRef(false);
const resolveGameForProfile = useResolveGameForProfile({
applicationId,
gameId
});
const { gameId: gameId2, gameRecord, isLoading } = resolveGameForProfile;
if (gameRecord == null) {
r44 = [c5427_7.NoMatch];
} else {
const r28 = [];
if (hasFlag(gameRecord.gameFlags, GameFlags.GAME_PROFILE_DISABLED)) {
r28.push(c5427_7.Disabled);
}
const isAgeRestrictedContentClassification = _utils.isAgeRestrictedContentClassification(gameRecord.contentClassification);
r44 = r28;
if (isAgeRestrictedContentClassification) {
r28.push(c5427_7.NSFW);
r44 = r28;
}
}
const game_profile_available = r44.length === 0;
useEffect(() => {
let rejection_reason;
if (!ref.current && c16609_1 && !isLoading && gameRecord != null) {
Module38(source != null, "Cannot track a Game Profile Entry Point Impressions without a source.");
if (gameRecord == null) {
rejection_reason = [c5427_7.NoMatch];
} else {
const r21 = [];
if (hasFlag(gameRecord.gameFlags, GameFlags.GAME_PROFILE_DISABLED)) {
r21.push(c5427_7.Disabled);
}
const isAgeRestrictedContentClassification = _utils.isAgeRestrictedContentClassification(gameRecord.contentClassification);
rejection_reason = r21;
if (isAgeRestrictedContentClassification) {
r21.push(c5427_7.NSFW);
rejection_reason = r21;
}
}
AnalyticsUtils.track(AnalyticEvents.GAME_PROFILE_ENTRY_POINT_AVAILABLE, {
game_profile_available,
application_id: gameRecord.id,
rejection_reason,
source
});
ref.current = true;
}
}, [gameRecord, game_profile_available, isLoading, source, trackEntryPointImpression]);
return {
shouldOpenGameProfile: game_profile_available,
gameId: gameId2
};
};
export function gameIsAcceptable(a0) {
let r27;
if (a0 == null) {
r27 = [c5427_7.NoMatch];
} else {
const r4 = [];
if (hasFlag(a0.gameFlags, GameFlags.GAME_PROFILE_DISABLED)) {
r4.push(c5427_7.Disabled);
}
const isAgeRestrictedContentClassification = _utils.isAgeRestrictedContentClassification(a0.contentClassification);
r27 = r4;
if (isAgeRestrictedContentClassification) {
r4.push(c5427_7.NSFW);
r27 = r4;
}
}
return r27.length === 0;
}
export function gameIdIsAcceptable(a0) {
let r30;
const game = GameStore.getGame(a0);
if (game == null) {
r30 = [c5427_7.NoMatch];
} else {
const r12 = [];
if (hasFlag(game.gameFlags, GameFlags.GAME_PROFILE_DISABLED)) {
r12.push(c5427_7.Disabled);
}
const isAgeRestrictedContentClassification = _utils.isAgeRestrictedContentClassification(game.contentClassification);
r30 = r12;
if (isAgeRestrictedContentClassification) {
r12.push(c5427_7.NSFW);
r30 = r12;
}
}
return r30.length === 0;
}
@@ -0,0 +1,39 @@
// Metro module 11923 (f11924).
import GameStore from "../../games/GameStore";
import UserStore from "../../../stores/UserStore";
import { SIMILAR_GAMES_BLOCKED_GAME_IDS } from "../../../_bundle/Module8657";
import { useSimilarGameIds } from "../GameProfileHttpUtils";
import { useGames } from "../../games/hooks/useGame";
import { useStateFromStores, useStateFromStoresArray } from "../../../_bundle/Module589";
import { gameIsAcceptable } from "./useShouldOpenGameProfileModal";
import { isGameProfileObscured } from "./useGameProfileObscured";
let c8177_5 = [];
const similarGames = [];
export default function useSimilarGames(a0, a1) {
let r13;
const r2 = a1 ? !SIMILAR_GAMES_BLOCKED_GAME_IDS.has(a0) : a1;
const similarGameIds = useSimilarGameIds(a0, r2);
const { data, isLoading, error } = similarGameIds;
if (r2) {
r13 = data;
if (r13 == null) {
r13 = c8177_5;
}
} else {
r13 = c8177_5;
}
let c19274_0 = r13;
useGames(r13);
const stateFromStores = useStateFromStores([GameStore], () => c19274_0.some((item) => GameStore.getGame(item) == null && !GameStore.hasNoData(item) && !GameStore.didFetchingFail(item)), [r13]);
const stateFromStoresArray = useStateFromStoresArray([GameStore, UserStore], () => {
const nsfwAllowed = UserStore.getCurrentUser()?.nsfwAllowed;
return c19274_0.map((item) => GameStore.getGame(item)).filter((item) => item != null).filter((item) => gameIsAcceptable(item) && !isGameProfileObscured(item, nsfwAllowed));
}, [r13]);
return r2 ? {
isFetching: error == null && data == null || isLoading || stateFromStores,
similarGames: stateFromStoresArray
} : {
isFetching: false,
similarGames
};
};
@@ -0,0 +1,42 @@
// Metro module 8491 (f8492).
import GameStore from "../../games/GameStore";
import { Distributors } from "../../../Constants";
import { useStateFromStores } from "../../../_bundle/Module589";
import { SteamReleaseStatus } from "../../../_bundle/Module8492";
import { ThirdPartyGameApplicationWebsiteCategory } from "../../../_bundle/Module8490";
import { isNullOrEmpty } from "../../../utils/StringUtils";
export function buildSteamStoreUrl(a0) {
return `https://store.steampowered.com/app/${encodeURIComponent(a0)}`;
}
export function useSteamWebsiteUrl(a0) {
return useStateFromStores([GameStore], () => {
let r42;
if (a0 == null) {
return null;
}
const game = GameStore.getGame(a0);
if (game == null) {
return null;
}
if (game.steamReleaseStatus === SteamReleaseStatus.RETIRED_ABANDONED) {
return null;
}
const url = game.websites.find((website) => website.category === ThirdPartyGameApplicationWebsiteCategory.STEAM)?.url;
const r25 = game.thirdPartySkus.filter((thirdPartySku) => thirdPartySku.distributor === Distributors.STEAM && !isNullOrEmpty(thirdPartySku.id));
const id = r25[0]?.id;
let r34 = isNullOrEmpty(id) ? null : `https://store.steampowered.com/app/${encodeURIComponent(id)}`;
L16: {
if (r25.length > 1) {
r42 = url;
if (r42 != null) {
break L16;
}
}
if (r34 == null) {
r34 = url ?? null;
}
r42 = r34;
}
return r42;
}, [a0]);
}
@@ -0,0 +1,11 @@
// Metro module 8493 (f8494).
import { Distributors } from "../../../Constants";
import { isNullOrEmpty } from "../../../utils/StringUtils";
import { buildXboxGamePassStoreUrl } from "../../activities/utils/distributorStoreUrls";
export default function useXboxGamePassStoreUrl(a0) {
if (a0 == null) {
return null;
}
const r8 = a0.thirdPartySkus.find((thirdPartySku) => thirdPartySku.distributor === Distributors.XBOX_GAME_PASS && !isNullOrEmpty(thirdPartySku.id));
return r8?.id == null ? null : buildXboxGamePassStoreUrl(r8.id);
};
@@ -0,0 +1,9 @@
// Metro module 11944 (f11945).
import { gameFromServer } from "../../../stores/DetectableGameStore";
import { DETECTABLE_GAMES_CDN_URL } from "../../game_detection/Constants";
import { HTTP } from "../../../_bundle/sendRequest";
export async function fetchDetectableGames() {
let c27213_0;
c27213_0 = void 0;
return (await HTTP.get(DETECTABLE_GAMES_CDN_URL)).body.map(gameFromServer);
}
@@ -0,0 +1,168 @@
// Metro module 11943 (f11944).
import { useState, useMemo, useEffect, useCallback, useLayoutEffect } from "react";
import { ScrollView, View } from "react-native";
import { createStyles } from "../../../../design/components/Styles/native/createStyles";
import Module712 from "../../../../_bundle/Module712";
import { useNavigation } from "../../../../design/components/Navigator/native/useNavigation.native";
import { generateViewId, trackGameProfileFeedback } from "../../GameProfileAnalyticUtils";
import { fetchDetectableGames } from "../GameDetectionReportActionCreators";
import ModalActionCreators from "../../../../actions/ModalActionCreators";
import { intl, t } from "../../../../intl/index.native";
import { HeaderActionButton } from "../../../../design/components/Navigator/native/HeaderActionButton.native";
import { XSmallIcon } from "../../../../design/components/Icon/native/redesign/generated/XSmallIcon";
import { getHeaderBackButton } from "../../../../design/components/Navigator/native/NavigatorHeader.native";
import { Text } from "../../../../design/components/Text/native/Text";
import { TableRadioGroup } from "../../../../design/components/TableRow/native/TableRadioGroup.native";
import { TableRadioRow } from "../../../../design/components/TableRow/native/TableRadioRow.native";
import { TextInput } from "../../../../design/components/TextInput/native/TextInput.native";
import { Button } from "../../../../design/components/Button/native/Button.native";
import { TextArea } from "../../../../design/components/TextInput/native/TextArea.native";
import { Navigator } from "../../../../design/components/Navigator/native/Navigator.native";
let c8190_10, useStyles, name;
const ReportContent = function ReportContent(props) {
let callback, memo2;
const applicationId = props.applicationId;
callback = void 0;
memo2 = void 0;
const styles = useStyles();
const navigation = useNavigation();
const [state, setState] = useState("issue_selection");
const [state2, setState2] = useState([]);
const [state3, setState3] = useState("");
const [state4, setState4] = useState(null);
const [state5, onChange2] = useState("");
const memo = useMemo(() => generateViewId(), []);
useEffect(() => {
fetchDetectableGames().then(setState2).catch(() => {});
}, []);
callback = useCallback(() => {
ModalActionCreators.popWithKey(c8190_10);
}, []);
useLayoutEffect(() => {
if (state === "issue_selection") {
navigation.setOptions({
title: intl.string(t["6tnjbD"]),
headerLeft: () => null,
headerRight: () => <HeaderActionButton IconComponent={XSmallIcon} accessibilityLabel={intl.string(t.cpT0Cq)} onPress={callback} />
});
} else if (state === "game_search") {
navigation.setOptions({
title: intl.string(t.TZgkxY),
headerLeft: getHeaderBackButton(() => setState("issue_selection")),
headerRight: () => null
});
} else {
navigation.setOptions({
title: intl.string(t.tdDpJj),
headerLeft: getHeaderBackButton(() => setState("issue_selection")),
headerRight: () => null
});
}
}, [state, navigation, callback]);
const callback2 = useCallback(() => {
const suggestedGameName = state3.trim() !== "" ? state3.trim() : void 0;
let suggestedGameApplicationId = state4?.id;
if (suggestedGameApplicationId == null) {
suggestedGameApplicationId = null;
}
trackGameProfileFeedback({
viewId: memo,
applicationId,
suggestedGameName,
suggestedGameApplicationId,
feedback: state5.trim() !== "" ? state5.trim() : void 0,
submitted: true
});
callback();
}, [memo, applicationId, state3, state4, state5, callback]);
memo2 = useMemo(() => {
if (state3.trim() === "") {
return [];
}
let c27212_0 = state3.toLowerCase();
return state2.filter((item) => item.name.toLowerCase().includes(c27212_0)).slice(0, 10);
}, [state2, state3]);
return <ScrollView style={styles.container} keyboardShouldPersistTaps="handled">
{state === "issue_selection" ? <View style={styles.content}>
<Text variant="text-sm/normal" color="text-muted">
{intl.string(t.IQHicr)}
</Text>
<TableRadioGroup value={void 0} onChange={(c30475_0) => {
setTimeout(() => {
setState(c30475_0 === "wrong_game_shown" ? "game_search" : "other_feedback");
}, 100);
}} hasIcons={false}>
<TableRadioRow value="wrong_game_shown" label={intl.string(t.TZgkxY)} />
<TableRadioRow value="other_feedback" label={intl.string(t.tdDpJj)} />
</TableRadioGroup>
</View> : state === "game_search" ? <>
<View style={styles.content}>
<Text variant="text-sm/normal" color="text-muted">
{intl.string(t["79o/iq"])}
</Text>
<TextInput value={state3} onChange={(event) => {
setState3(event);
if (state4 != null && event !== state4.name) {
setState4(null);
}
}} placeholder={intl.string(t["/SGi7v"])} />
{memo2.length > 0 && <TableRadioGroup value={state4?.id} onChange={(c30476_0) => {
let r8 = memo2.find((item) => item.id === c30476_0);
if (r8 == null) {
r8 = null;
}
setState4(r8);
if (r8 != null) {
setState3(r8.name);
}
}} hasIcons={false}>
{memo2.map((item, index) => <TableRadioRow key={`${item.id}-${index}`} value={item.id} label={item.name} />)}
</TableRadioGroup>}
</View>
<View style={styles.submitContainer}>
<Button variant="primary" size="md" text={intl.string(t.geKm7t)} disabled={state3.trim() === ""} onPress={callback2} />
</View>
</> : state === "other_feedback" ? <>
<View style={styles.content}>
<Text variant="text-sm/normal" color="text-muted">
{intl.string(t.IblYEw)}
</Text>
<TextArea value={state5} onChange={onChange2} placeholder={intl.string(t.aiPKV4)} maxLength={300} />
</View>
<View style={styles.submitContainer}>
<Button variant="primary" size="md" text={intl.string(t.geKm7t)} disabled={state5.trim() === ""} onPress={callback2} />
</View>
</> : void 0}
</ScrollView>;
};
c8190_10 = "game-detection-report";
useStyles = createStyles({
container: {
flex: 1,
backgroundColor: Module712.colors.BACKGROUND_BASE_LOW
},
content: {
padding: Module712.space.PX_16,
gap: Module712.space.PX_24
},
submitContainer: {
padding: Module712.space.PX_16
}
});
name = "REPORT";
export default function GameDetectionReportModal(props) {
const applicationId2 = props.applicationId;
return <Navigator screens={useMemo(() => {
const r0 = {};
r0[name] = {
render: (a0) => <ReportContent {...a0} />
};
return r0;
}, [])} initialRouteStack={[{
name,
params: {
applicationId: applicationId2
}
}]} />;
};
export const MODAL_KEY = "game-detection-report";
@@ -0,0 +1,376 @@
// Metro module 8650 (f8651).
import { memo, useCallback } from "react";
import { ActivityIndicator, Image as Image2, Pressable, ScrollView, View } from "react-native";
import { getParser } from "../../../markup/CustomMarkup.native";
import { intl, t } from "../../../../intl/index.native";
import { createStyles } from "../../../../design/components/Styles/native/createStyles";
import Module712 from "../../../../_bundle/Module712";
import { getPosterUrl, getPollExpiryLabel } from "../../AnnouncementMessageUtils";
import { Text } from "../../../../design/components/Text/native/Text";
import { ImageWithPlaceholder } from "../../../../components_native/common/ImageWithPlaceholder";
import { dateFormat } from "../../../../utils/DateUtils";
import { ReactionIcon } from "../../../../design/components/Icon/native/redesign/generated/ReactionIcon";
import useAnalyticsLocations from "../../../app_analytics/useAnalyticsLocations";
import useGameAnnouncements from "../../hooks/useGameAnnouncements";
import { GameProfileTrackActionActions } from "../../GameProfileAnalyticUtils";
import GameProfileActionCreators_native from "../../GameProfileActionCreators.native";
import navigateToGameAnnouncement from "../../navigateToGameAnnouncement";
import { Button } from "../../../../design/components/Button/native/Button.native";
import { ChevronSmallRightIcon } from "../../../../design/components/Icon/native/redesign/generated/ChevronSmallRightIcon";
let c5627_12, parser, c5627_14, useStyles, MessageAnnouncementCard, PollAnnouncementCard, Component;
const EmbedAnnouncementCard = function EmbedAnnouncementCard(props) {
const { message, onPress: onPress2, guildId: guildId2, channelId: channelId2 } = props;
const styles2 = useStyles();
if (parser == null) {
parser = getParser();
}
const r23 = parser;
let r43 = message.media?.proxyUrl;
if (r43 == null) {
r43 = message.media?.url;
}
let uri = r43 != null ? getPosterUrl(r43, 160, c5627_12) : null;
if (uri == null) {
uri = r43;
}
const embedSource = message.embedSource;
if (embedSource == null) {
return null;
}
const r14 = embedSource.color != null ? {
borderLeftColor: embedSource.color
} : void 0;
const props2 = {
style: styles2.card,
onPress: () => onPress2(message.id),
accessibilityRole: "button",
accessibilityLabel: message.title,
children: null
};
const r70 = [embedSource.url != null && <Text variant="text-xs/medium" color="text-link" lineClamp={1}>{embedSource.url}</Text>, ,];
const r90 = [embedSource.authorName != null && <View style={styles2.embedAuthorRow}>
{embedSource.authorIconUrl != null && <Image2 source={{
uri: embedSource.authorIconUrl
}} style={styles2.embedAuthorIcon} />}
<Text variant="text-xs/semibold" color="text-strong" lineClamp={1}>{embedSource.authorName}</Text>
</View>, message.media != null && uri != null && <View style={styles2.embedMedia}>
<ImageWithPlaceholder uri={uri} placeholder={message.media.placeholder} placeholderVersion={message.media.placeholderVersion} style={styles2.mediaImage} />
</View>, message.title != null && <Text variant="text-md/semibold" color="mobile-text-heading-primary" lineClamp={2}>
{r23(message.title, true, {
guildId: guildId2,
channelId: channelId2
})}
</Text>, message.body.length > 0 && <Text variant="text-sm/medium" color="text-default" lineClamp={3}>
{r23(message.body, true, {
guildId: guildId2,
channelId: channelId2
})}
</Text>, ,];
const r142 = [embedSource.providerIconUrl != null && <Image2 source={{
uri: embedSource.providerIconUrl
}} style={styles2.embedProviderIcon} />, <Text variant="text-xs/medium" color="text-muted">
{embedSource.providerName != null ? `${embedSource.providerName} · ` : ""}
{dateFormat(new Date(message.timestamp), "LL")}
</Text>, ,];
let r169 = message.reactionCount > 0;
if (r169) {
const r182 = [<ReactionIcon size="xs" color={Module712.colors.TEXT_MUTED} />, ,];
const reactionCount = message.reactionCount;
if (!(c5627_14 != null && c5627_14.locale === intl.currentLocale)) {
c5627_14 = {
locale: intl.currentLocale,
format: new Intl.NumberFormat(intl.currentLocale)
};
}
r182[1] = <Text variant="text-xs/medium" color="text-muted">
{c5627_14.format.format(reactionCount)}
</Text>;
r169 = <View style={styles2.reactionInfo}>{r182}</View>;
}
r142[2] = r169;
r90[4] = <View style={styles2.metadataRow}>{r142}</View>;
r70[1] = <View style={[styles2.embedContentArea, r14]}>{r90}</View>;
props2.children = <View style={styles2.cardBody}>{r70}</View>;
return <Pressable {...props2} />;
};
MessageAnnouncementCard = function MessageAnnouncementCard(props) {
const { message: message2, onPress: onPress3, guildId: guildId2, channelId: channelId2 } = props;
const styles2 = useStyles();
if (parser == null) {
parser = getParser();
}
const r20 = parser;
let r39 = message2.media?.proxyUrl;
if (r39 == null) {
r39 = message2.media?.url;
}
let uri = r39 != null ? getPosterUrl(r39, 160, c5627_12) : null;
if (uri == null) {
uri = r39;
}
const props2 = {
style: styles2.card,
onPress: () => onPress3(message2.id),
accessibilityRole: "button",
accessibilityLabel: message2.title,
children: null
};
const children = [message2.media != null && uri != null && <View style={styles2.smallCardMedia}>
<ImageWithPlaceholder uri={uri} placeholder={message2.media.placeholder} placeholderVersion={message2.media.placeholderVersion} style={styles2.mediaImage} />
</View>, ,];
const r83 = [message2.title != null && <Text variant="text-md/semibold" color="mobile-text-heading-primary" lineClamp={2}>
{r20(message2.title, true, {
guildId: guildId2,
channelId: channelId2
})}
</Text>, message2.body.length > 0 && <Text variant="text-sm/medium" color="text-default" lineClamp={3}>
{r20(message2.body, true, {
guildId: guildId2,
channelId: channelId2
})}
</Text>, ,];
const r115 = [<Text variant="text-xs/medium" color="text-muted">
{dateFormat(new Date(message2.timestamp), "LL")}
</Text>, ,];
let r117 = message2.reactionCount > 0;
if (r117) {
const r130 = [<ReactionIcon size="xs" color={Module712.colors.TEXT_MUTED} />, ,];
const reactionCount = message2.reactionCount;
if (!(c5627_14 != null && c5627_14.locale === intl.currentLocale)) {
c5627_14 = {
locale: intl.currentLocale,
format: new Intl.NumberFormat(intl.currentLocale)
};
}
r130[1] = <Text variant="text-xs/medium" color="text-muted">
{c5627_14.format.format(reactionCount)}
</Text>;
r117 = <View style={styles2.reactionInfo}>{r130}</View>;
}
r115[1] = r117;
r83[2] = <View style={styles2.metadataRow}>{r115}</View>;
children[1] = <View style={styles2.cardBody}>{r83}</View>;
props2.children = children;
return <Pressable {...props2} />;
};
PollAnnouncementCard = function PollAnnouncementCard(props) {
const { message: message3, onPress: onPress4 } = props;
const styles = useStyles();
const poll = message3.poll;
if (poll == null) {
return null;
}
const r15 = poll.answers.slice(0, 3);
const count = poll.answers.length - r15.length;
return <Pressable style={styles.card} onPress={() => onPress4(message3.id)} accessibilityRole="button" accessibilityLabel={poll.question.text}>
<View style={styles.cardBody}>
<Text variant="text-md/semibold" color="mobile-text-heading-primary">{poll.question.text}</Text>
<View style={styles.pollAnswers}>
{r15.map((item) => {
let text = item.poll_media.text;
if (text == null) {
text = "";
}
return <View key={item.answer_id} style={styles.pollAnswerOption}>
<Text variant="text-sm/medium" color="text-default" lineClamp={1}>{text}</Text>
</View>;
})}
{count > 0 && <Text variant="text-xs/medium" color="text-muted" style={styles.pollMoreOptions}>
{intl.format(t["mv/nIa"], {
count
})}
</Text>}
</View>
<View style={styles.metadataRow}>
<Text variant="text-xs/medium" color="text-muted">
{intl.format(t.t0FTsH, {
createdAt: new Date(message3.timestamp),
expiryLabel: getPollExpiryLabel(poll)
})}
</Text>
</View>
</View>
</Pressable>;
};
c5627_12 = 120;
parser = null;
c5627_14 = null;
useStyles = createStyles({
container: {
gap: Module712.space.PX_8
},
smallCardsScroller: {
marginHorizontal: -Module712.space.PX_16,
overflow: "visible"
},
smallCardsContainer: {
flexDirection: "row",
gap: Module712.space.PX_12,
paddingHorizontal: Module712.space.PX_16
},
sectionHeader: {
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
paddingHorizontal: Module712.space.PX_8
},
loadingContainer: {
height: 120,
alignItems: "center",
justifyContent: "center"
},
card: {
flexDirection: "column",
borderRadius: Module712.radii.lg,
overflow: "hidden",
backgroundColor: Module712.colors.BACKGROUND_BASE_LOW,
borderWidth: 1,
borderColor: Module712.colors.BORDER_SUBTLE,
width: 160
},
cardBody: {
flex: 1,
flexDirection: "column",
gap: Module712.space.PX_4,
overflow: "hidden",
padding: Module712.space.PX_12
},
smallCardMedia: {
height: 120,
overflow: "hidden",
flexShrink: 0
},
mediaImage: {
width: "100%",
height: "100%",
resizeMode: "cover"
},
metadataRow: {
flexDirection: "row",
alignItems: "center",
gap: Module712.space.PX_8,
marginTop: "auto"
},
reactionInfo: {
flexDirection: "row",
alignItems: "center",
gap: Module712.space.PX_4
},
embedContentArea: {
flex: 1,
gap: Module712.space.PX_4,
borderLeftWidth: 4,
borderLeftColor: Module712.colors.BORDER_SUBTLE,
borderTopLeftRadius: Module712.radii.xs,
borderBottomLeftRadius: Module712.radii.xs,
paddingLeft: Module712.space.PX_8
},
embedAuthorRow: {
flexDirection: "row",
alignItems: "center",
gap: Module712.space.PX_4
},
embedAuthorIcon: {
width: 20,
height: 20,
borderRadius: Module712.radii.round
},
embedProviderIcon: {
width: 16,
height: 16
},
embedMedia: {
overflow: "hidden",
borderRadius: Module712.radii.sm,
aspectRatio: 1.7777777777777777
},
pollAnswers: {
flexDirection: "column",
gap: Module712.space.PX_4,
flex: 1
},
pollAnswerOption: {
paddingVertical: Module712.space.PX_8,
paddingHorizontal: Module712.space.PX_12,
borderRadius: Module712.radii.sm,
backgroundColor: Module712.colors.BACKGROUND_BASE_LOWEST
},
pollMoreOptions: {
paddingHorizontal: Module712.space.PX_12
}
});
Component = memo(function(a0) {
return a0.message.poll != null ? <PollAnnouncementCard {...a0} /> : a0.message.embedSource != null ? <EmbedAnnouncementCard {...a0} /> : <MessageAnnouncementCard {...a0} />;
});
export default function GameProfileAnnouncements(props) {
let callback;
const { gameId, invite, closeModal, trackAction, scrollOffsetRef } = props;
callback = void 0;
const styles2 = useStyles();
const analyticsLocations = useAnalyticsLocations().analyticsLocations;
const gameAnnouncements = useGameAnnouncements(gameId, 10);
const { messages, channelId, guildId, loading } = gameAnnouncements;
const callback2 = useCallback(() => {
let guildId2 = invite == null ? void 0 : invite.guild?.id;
if (guildId2 == null) {
guildId2 = guildId;
}
if (guildId2 != null && channelId != null) {
trackAction(GameProfileTrackActionActions.Announcements);
GameProfileActionCreators_native.setGameProfilePendingReturn({
gameId,
channelId,
initialScrollOffset: scrollOffsetRef.current
});
closeModal();
navigateToGameAnnouncement({
invite,
guildId: guildId2,
channelId,
analyticsLocationStack: analyticsLocations
});
}
}, [trackAction, closeModal, invite, guildId, channelId, analyticsLocations, gameId, scrollOffsetRef]);
callback = useCallback((a0) => {
let guildId2 = invite == null ? void 0 : invite.guild?.id;
if (guildId2 == null) {
guildId2 = guildId;
}
if (guildId2 != null && channelId != null) {
trackAction(GameProfileTrackActionActions.AnnouncementsItem);
GameProfileActionCreators_native.setGameProfilePendingReturn({
gameId,
channelId,
initialScrollOffset: scrollOffsetRef.current
});
closeModal();
navigateToGameAnnouncement({
invite,
guildId: guildId2,
channelId,
messageId: a0,
analyticsLocationStack: analyticsLocations
});
}
}, [trackAction, closeModal, invite, guildId, channelId, analyticsLocations, gameId, scrollOffsetRef]);
return loading ? <View style={styles2.container}>
<View style={styles2.sectionHeader}>
<Text variant="heading-sm/semibold" color="mobile-text-heading-primary">
{intl.string(t.B0BV3Y)}
</Text>
</View>
<View style={styles2.loadingContainer}>
<ActivityIndicator />
</View>
</View> : channelId == null ? null : messages.length !== 0 ? <View style={styles2.container}>
<View style={styles2.sectionHeader}>
<Text variant="heading-sm/semibold" color="mobile-text-heading-primary">
{intl.string(t.B0BV3Y)}
</Text>
<Button text={intl.string(t.budhsM)} variant="tertiary" size="sm" icon={<ChevronSmallRightIcon size="sm" />} iconPosition="end" onPress={callback2} />
</View>
<ScrollView horizontal showsHorizontalScrollIndicator={false} style={styles2.smallCardsScroller} contentContainerStyle={styles2.smallCardsContainer} decelerationRate="fast" snapToInterval={172} snapToStart={false} snapToEnd={false}>
{messages.map((a0) => <Component key={a0.id} message={a0} onPress={callback} guildId={guildId} channelId={channelId} />)}
</ScrollView>
</View> : null;
};
@@ -0,0 +1,250 @@
// Metro module 8647 (f8648).
import { useState, useRef, useEffect, useMemo, useCallback } from "react";
import { View } from "react-native";
import GuildMembershipStore from "../../../../stores/GuildMembershipStore";
import { createStyles } from "../../../../design/components/Styles/native/createStyles";
import Module712 from "../../../../_bundle/Module712";
import { ThirdPartyGameApplicationWebsiteCategory } from "../../../../_bundle/Module8490";
import { findCodedLink } from "../../../coded_links/findCodedLinks";
import { CodedLinkType } from "../../../coded_links/CodedLink";
import resolveInvite from "../../../instant_invite/resolveInvite";
import { useStateFromStores } from "../../../../_bundle/Module589";
import { GameProfileTrackActionActions } from "../../GameProfileAnalyticUtils";
import { transitionToGuild } from "../../../routing/transitionToGuild.native";
import { showInvite } from "../../../../actions/native/DisplayedInviteActionCreators";
import { fromInviteGuild } from "../../../../utils/GuildRecordUtils";
import { Text } from "../../../../design/components/Text/native/Text";
import { intl, t } from "../../../../intl/index.native";
import FastImage from "../../../../components_native/common/FastImage";
import AvatarUtils from "../../../../utils/AvatarUtils";
import GuildIcon, { GuildIconSizes } from "../../../guild/native/GuildIcon";
import GuildBadgeV2 from "../../../guild/native/GuildBadgeV2";
import { Icon } from "../../../../design/void/native";
import { Button } from "../../../../design/components/Button/native/Button.native";
const useStyles = createStyles({
container: {
gap: Module712.space.PX_8
},
headerText: {
paddingHorizontal: Module712.space.PX_8
},
card: {
borderRadius: Module712.radii.lg,
borderWidth: 1,
borderColor: Module712.colors.BORDER_SUBTLE,
overflow: "hidden",
backgroundColor: Module712.colors.BACKGROUND_BASE_LOW
},
guildBanner: {
height: 112,
width: "100%",
resizeMode: "cover"
},
guildContent: {
flexDirection: "column",
padding: Module712.space.PX_16,
gap: Module712.space.PX_16
},
guildIcon: {
width: 56,
height: 56,
borderRadius: Module712.radii.md,
overflow: "hidden",
borderWidth: Module712.space.PX_4,
borderColor: Module712.colors.BACKGROUND_BASE_LOW,
marginLeft: -Module712.space.PX_4
},
guildIconWithBanner: {
marginTop: -Module712.space.PX_48
},
guildIconImage: {
width: "100%",
height: "100%",
borderRadius: Module712.radii.none
},
guildInfo: {
flex: 1,
gap: Module712.space.PX_16
},
guildNameDescriptionContainer: {
gap: Module712.space.PX_4
},
guildNameRow: {
flexDirection: "row",
alignItems: "center",
gap: Module712.space.PX_4
},
memberCountsContainer: {
flexDirection: "row",
gap: Module712.space.PX_16
},
memberCountContainer: {
flexDirection: "row",
alignItems: "center",
gap: Module712.space.PX_4
},
onlineEllipse: {
width: 8,
height: 8,
borderRadius: Module712.radii.round,
backgroundColor: Module712.colors.STATUS_POSITIVE
},
membersEllipse: {
width: 8,
height: 8,
borderRadius: Module712.radii.round,
backgroundColor: Module712.colors.TEXT_DEFAULT
}
});
export default function GameProfileCommunityServer(props) {
let memo, stateFromStores;
const { game, trackAction, onInviteResolved, closeModal } = props;
memo = void 0;
stateFromStores = void 0;
const styles = useStyles();
const [state, setState] = useState(null);
const ref = useRef(onInviteResolved);
useEffect(() => {
ref.current = onInviteResolved;
}, [onInviteResolved]);
memo = useMemo(() => {
const r2 = game == null;
let r7 = void 0;
if (!r2) {
const websites = game.websites;
r7 = websites == null ? void 0 : websites.find((website) => website.category === ThirdPartyGameApplicationWebsiteCategory.DISCORD);
}
return r7;
}, [game?.websites]);
useEffect(() => {
let _resolve2 = function _resolve() {
const r9 = async () => {
let c31471_2 = 0;
let c31978_0, c31978_1, c31978_2;
L20: {
L19: {
try {
c31978_0 = void 0;
c31978_1 = void 0;
c31978_2 = void 0;
if (memo == null) {
break L20;
}
const r35 = findCodedLink(memo.url);
if (r35 == null) {
break L20;
}
if (r35.type === CodedLinkType.INVITE) {
c31471_2 = 1;
c31978_0 = await resolveInvite(r35.code, "game_profile");
c31978_1 = c31978_0.invite;
c31978_2 = c31978_0.banned;
if (c31978_1 != null && c31978_2 !== true) {
(0, setState)(c31978_1);
const current = ref.current;
if (current != null) {
current.call(ref, c31978_1);
}
}
c31471_2 = 0;
break L19;
}
break L20;
} catch ($e) {
let r28 = $e;
if (c31471_2 !== 0) {
while (true) {
try {
c31471_2 = 0;
break L19;
} catch ($e) {
r28 = $e;
if (c31471_2 === 0) {
break;
}
}
}
}
throw r28;
}
}
return void 0;
}
};
_resolve2 = r9;
return r9.apply(this, arguments);
};
if (memo != null) {
(function resolve() {
return _resolve2.apply(this, arguments);
})();
}
}, [memo]);
stateFromStores = useStateFromStores([GuildMembershipStore], () => (state == null ? void 0 : state.guild?.id) != null && GuildMembershipStore.isMember(state.guild.id));
const callback = useCallback(() => {
L7: {
if (state != null) {
trackAction(GameProfileTrackActionActions.JoinServer);
closeModal();
if (stateFromStores) {
if (state.guild?.id != null) {
transitionToGuild(state.guild.id);
break L7;
}
}
showInvite(state.code);
}
}
}, [state, stateFromStores, trackAction, closeModal]);
if (state != null && state.guild != null) {
const guild = fromInviteGuild(state.guild);
let approximate_member_count = state.approximate_member_count;
if (approximate_member_count == null) {
approximate_member_count = state.guild.approximate_member_count;
}
let approximate_presence_count = state.approximate_presence_count;
if (approximate_presence_count == null) {
approximate_presence_count = state.guild.approximate_presence_count;
}
const r88 = [<Text variant="heading-sm/semibold" color="mobile-text-heading-primary" style={styles.headerText}>
{intl.string(t["U2N+ci"])}
</Text>, ,];
const r100 = [guild.banner != null && <FastImage source={AvatarUtils.getGuildBannerSource(guild)} style={styles.guildBanner} />, ,];
r100[1] = <View style={styles.guildContent}>
<View style={[styles.guildIcon, guild.banner != null ? styles.guildIconWithBanner : null]}>
<GuildIcon guild={guild} size={GuildIconSizes.LARGE} style={styles.guildIconImage} />
</View>
<View style={styles.guildInfo}>
<View style={styles.guildNameDescriptionContainer}>
<View style={styles.guildNameRow}>
<Text variant="text-md/semibold" color="mobile-text-heading-primary" lineClamp={1}>{guild.name}</Text>
<GuildBadgeV2 guild={guild} size={Icon.Sizes.REFRESH_SMALL_16} />
</View>
<Text variant="text-sm/medium" color="text-default" lineClamp={3}>{guild.description}</Text>
</View>
<View style={styles.memberCountsContainer}>
{approximate_presence_count != null ? <View style={styles.memberCountContainer}>
<View style={styles.onlineEllipse} />
<Text variant="text-xs/normal" color="text-default">
{intl.formatToPlainString(t["LC+S+m"], {
membersOnline: approximate_presence_count
})}
</Text>
</View> : null}
{approximate_member_count != null ? <View style={styles.memberCountContainer}>
<View style={styles.membersEllipse} />
<Text variant="text-xs/normal" color="text-default">
{intl.formatToPlainString(t.zRl6XR, {
count: approximate_member_count
})}
</Text>
</View> : null}
</View>
</View>
<Button variant="secondary" size="md" text={stateFromStores ? intl.string(t.cEnaWx) : intl.string(t.XpeFYr)} onPress={callback} />
</View>;
r88[1] = <View style={styles.card}>{r100}</View>;
return <View style={styles.container}>{r88}</View>;
}
return null;
};
@@ -0,0 +1,149 @@
// Metro module 11924 (f11925).
import { useCallback, useMemo } from "react";
import { Pressable, View } from "react-native";
import { IGDB_ATTRIBUTION_LINK } from "../../../content_inventory/ContentInventoryConstants";
import { createStyles } from "../../../../design/components/Styles/native/createStyles";
import Module712 from "../../../../_bundle/Module712";
import Linking from "../../../../lib/native/Linking";
import { getGenreText } from "../../../../utils/SKUUtils";
import { intl, t } from "../../../../intl/index.native";
import { GameCompanyRole } from "../../../../flow/Server";
import { dateFormat } from "../../../../utils/DateUtils";
import { GameUpdatePlatformIcon } from "../../../game_update/native/GameUpdatePlatformIcon";
import getGameProfileWebsiteData from "../utils/getGameProfileWebsiteData";
import { Text } from "../../../../design/components/Text/native/Text";
let useStyles;
const GameProfileWebsiteButton = function GameProfileWebsiteButton(props) {
const { icon, action, title, trackAction, url } = props;
return <Pressable accessibilityRole="button" accessibilityLabel={title} onPress={useCallback(() => {
Linking.openURL(url);
trackAction(action);
}, [trackAction, action, url])} hitSlop={Module712.space.PX_4}>{icon}</Pressable>;
};
useStyles = createStyles({
container: {
gap: Module712.space.PX_8
},
headerText: {
paddingHorizontal: Module712.space.PX_8
},
detailsContainer: {
borderRadius: Module712.radii.lg,
borderWidth: 1,
borderColor: Module712.colors.BORDER_SUBTLE,
overflow: "hidden",
backgroundColor: Module712.colors.BACKGROUND_BASE_LOW
},
detailsRow: {
flexDirection: "row",
alignItems: "center",
justifyContent: "space-between",
padding: Module712.space.PX_12
},
detailsRowValue: {
flexDirection: "column",
flexShrink: 1,
paddingLeft: Module712.space.PX_32
},
detailsRowBottomBorder: {
borderBottomWidth: 1,
borderBottomColor: Module712.colors.BORDER_SUBTLE
},
platformsContainer: {
flexDirection: "row",
alignItems: "center",
gap: Module712.space.PX_12
},
linksContainer: {
flexDirection: "row",
alignItems: "center",
gap: Module712.space.PX_12
}
});
export default function GameProfileDetails(props) {
const { game, trackAction: trackAction2 } = props;
const styles = useStyles();
const memo = useMemo(() => {
if (game == null) {
return [];
}
const value = game == null ? void 0 : game.genres.map(getGenreText).join(", ");
const r26 = value != null && value !== "";
const r28 = [];
if (r26) {
r28.push({
label: game.genres.length !== 1 ? intl.string(t.pDgwYB) : intl.string(t.mjFKqn),
value
});
}
const r59 = game == null ? void 0 : game.getCompanyByRole(GameCompanyRole.PUBLISHER);
const value2 = r59.map((item) => item.name).join(", ");
if (value2 != null && value2 !== "") {
r28.push({
label: r59.length !== 1 ? intl.string(t.Hc7Enk) : intl.string(t["4Byy/G"]),
value: value2
});
}
const r108 = game == null ? void 0 : game.getCompanyByRole(GameCompanyRole.DEVELOPER);
const value3 = r108.map((item) => item.name).join(", ");
if (value3 != null && value3 !== "") {
r28.push({
label: r108.length !== 1 ? intl.string(t.KATEJB) : intl.string(t.na3PT0),
value: value3
});
}
const firstReleaseDate = game?.firstReleaseDate;
if (firstReleaseDate != null && firstReleaseDate !== "") {
r28.push({
label: intl.string(t.H3mPDT),
value: dateFormat(new Date(firstReleaseDate), "LL")
});
}
const platforms = game?.platforms;
if (platforms != null && platforms.length > 0) {
r28.push({
label: game.platforms.length !== 1 ? intl.string(t.PNqxNe) : intl.string(t["UxAag+"]),
value: <View style={styles.platformsContainer}>
{platforms.map((a0) => <GameUpdatePlatformIcon key={a0} platform={a0} size="md" color={Module712.colors.ICON_SUBTLE} />)}
</View>
});
}
const r237 = game == null;
let r238 = void 0;
if (!r237) {
const websites = game.websites;
r238 = websites == null ? void 0 : websites.map((website) => getGameProfileWebsiteData(website, Module712.colors.ICON_SUBTLE)).filter((item) => item != null);
}
if (r238 == null) {
r238 = [];
}
if (r238 != null && r238.length > 0) {
r28.push({
label: intl.string(t["Oj3o1/"]),
value: <View style={styles.linksContainer}>
{r238.map(({ title, icon, action: action2, url: url2 }) => <GameProfileWebsiteButton key={url2} icon={icon} action={action2} title={title} url={url2} trackAction={trackAction2} />)}
</View>
});
}
if (r28.length > 0) {
r28.push({
label: intl.string(t["BwQ+9e"]),
value: intl.format(t.XPFZVl, {
igdbLink: IGDB_ATTRIBUTION_LINK
})
});
}
return r28;
}, [styles.linksContainer, styles.platformsContainer, game, trackAction2]);
return memo.length !== 0 ? <View style={styles.container}>
<Text variant="heading-sm/semibold" color="mobile-text-heading-primary" style={styles.headerText}>
{intl.string(t["7OjmmH"])}
</Text>
<View style={styles.detailsContainer}>
{memo.map((item, index) => <View key={item.label} style={[styles.detailsRow, memo.length > 1 ? index < memo.length - 1 ? styles.detailsRowBottomBorder : null : null]}>
<Text variant="text-sm/medium" color="text-subtle" lineClamp={1}>{item.label}</Text>
{typeof item.value === "string" ? <Text variant="text-sm/normal" color="text-subtle" lineClamp={1} style={styles.detailsRowValue}>{item.value}</Text> : item.value}
</View>)}
</View>
</View> : null;
};
@@ -0,0 +1,18 @@
// Metro module 11941 (f11942).
import { useCallback } from "react";
import { RelativeMarketingURLs } from "../../../../Constants";
import { GameProfileTrackActionActions } from "../../GameProfileAnalyticUtils";
import MobileWebHandoffLinking from "../../../mobile_web_handoff/native/MobileWebHandoffLinking";
import { GameLinkTypes } from "../../../../flow/Server";
import { Button } from "../../../../design/components/Button/native/Button.native";
import { intl, t } from "../../../../intl/index.native";
export default function GameProfileGameClaimCta(props) {
const { game, trackAction } = props;
const callback = useCallback(async () => {
trackAction(GameProfileTrackActionActions.ClaimGame);
await MobileWebHandoffLinking.redirectDeveloperPortalWithHandoffToken(RelativeMarketingURLs.DEVELOPER_PORTAL_APPLICATIONS_GAME_IDENTITY);
}, [trackAction]);
const linkedApplications = game.linkedApplications;
const r18 = linkedApplications == null ? void 0 : linkedApplications.some((linkedApplication) => linkedApplication.type === GameLinkTypes.OFFICIAL);
return r18 != null ? r18 ? null : <Button variant="secondary" size="md" text={intl.string(t["mqg+to"])} onPress={callback} /> : <Button variant="secondary" size="md" text={intl.string(t["mqg+to"])} onPress={callback} />;
};
@@ -0,0 +1,155 @@
// Metro module 8516 (f8517).
import { useState, useMemo, useCallback } from "react";
import { Image as Image2, View } from "react-native";
import { createStyles } from "../../../../design/components/Styles/native/createStyles";
import Module712 from "../../../../_bundle/Module712";
import ReanimatedRexport, { useSharedValue, useAnimatedStyle } from "../../../reanimated/ReanimatedRexport";
import { getGenreText } from "../../../../utils/SKUUtils";
import Module4611 from "../../../../_bundle/Module4611";
import GameProfileRankPill from "./GameProfileRankPill";
import { Text } from "../../../../design/components/Text/native/Text";
const useStyles = createStyles({
container: {
backgroundColor: Module712.colors.BACKGROUND_BASE_LOWEST
},
artHero: {
width: "100%",
position: "absolute",
top: 0,
bottom: -Module712.space.PX_80,
left: 0,
right: 0
},
artHeroImage: {
height: "100%",
width: "100%",
resizeMode: "cover"
},
artHeroGradient: {
position: "absolute",
top: 0,
bottom: 0,
left: 0,
right: 0
},
headerContent: {
paddingTop: Module712.space.PX_32,
paddingHorizontal: Module712.space.PX_16,
gap: Module712.space.PX_12,
flexDirection: "row",
alignItems: "flex-end",
maxWidth: 520,
alignSelf: "center",
width: "100%"
},
shadowContainer: {
borderRadius: Module712.radii.sm,
...Module712.shadows.SHADOW_LOW
},
coverContainer: {
width: 85,
height: 114,
borderRadius: Module712.radii.sm,
backgroundColor: Module712.colors.BACKGROUND_BASE_LOW,
overflow: "hidden"
},
iconContainer: {
width: 85,
height: 85,
borderRadius: Module712.radii.sm,
backgroundColor: Module712.colors.BACKGROUND_BASE_LOW,
overflow: "hidden"
},
image: {
width: "100%",
height: "100%"
},
titleContainer: {
flex: 1,
flexDirection: "column",
alignItems: "flex-start"
},
textShadow: {
textShadowColor: Module712.colors.BLACK,
textShadowOffset: {
width: 0,
height: 0
},
textShadowRadius: 1
}
});
const __initData = {
code: "function GameProfileHeaderTsx1(){const{effectiveScrollY}=this.__closure;return{top:-Math.max(0,-effectiveScrollY.get())};}"
};
export default function GameProfileHeader(props) {
let sharedValue;
const game = props.game;
let scrollY = props.scrollY;
const onHeightMeasured = props.onHeightMeasured;
sharedValue = void 0;
const styles = useStyles();
const [state] = useState(() => Math.random());
const sharedValue2 = useSharedValue(0);
if (scrollY == null) {
scrollY = sharedValue2;
}
sharedValue = scrollY;
const _ = function _() {
return {
top: -Math.max(0, -sharedValue.get())
};
};
_.__closure = {
effectiveScrollY: sharedValue
};
_.__workletHash = 1177397229282;
_.__initData = __initData;
const animatedStyle = useAnimatedStyle(_);
const name = game?.name;
const r43 = game == null ? void 0 : game.genres.map(getGenreText).join(", ");
const l30Rank = game?.l30Rank;
const memo = useMemo(() => {
let r3 = game == null ? void 0 : game.getBannerURL(1024);
if (r3 == null) {
r3 = game?.screenshotUrls != null ? game.screenshotUrls.length > 0 ? game.screenshotUrls[Math.floor(state * game.screenshotUrls.length)] : null : null;
}
return r3;
}, [game, state]);
const memo2 = useMemo(() => game == null ? void 0 : game.getCoverURL(114), [game]);
const memo3 = useMemo(() => game == null ? void 0 : game.getIconURL(114), [game]);
const props2 = {
style: styles.container,
onLayout: useCallback((a0) => {
if (onHeightMeasured != null) {
onHeightMeasured(a0.nativeEvent.layout.height);
}
}, [onHeightMeasured]),
children: null
};
props2.children = [<ReanimatedRexport.View style={[styles.artHero, animatedStyle]}>
{memo != null && <Image2 source={{
uri: memo
}} style={styles.artHeroImage} />}
<Module4611 colors={["rgba(0,0,0,0.3)", styles.container.backgroundColor]} style={styles.artHeroGradient} />
</ReanimatedRexport.View>, <View style={styles.headerContent}>
<View style={styles.shadowContainer}>
<View {...memo2 != null ? {
style: styles.coverContainer,
children: <Image2 source={{
uri: memo2
}} style={styles.image} />
} : {
style: styles.iconContainer,
children: memo3 != null && <Image2 source={{
uri: memo3
}} style={styles.image} />
}} />
</View>
<View style={styles.titleContainer}>
{l30Rank != null && <GameProfileRankPill rank={l30Rank} />}
<Text variant="heading-xxl/semibold" color="text-overlay-light" lineClamp={2} style={styles.textShadow}>{name}</Text>
{r43 != null ? r43 !== "" ? <Text variant="text-md/normal" color="text-overlay-light" lineClamp={2} style={styles.textShadow}>{r43}</Text> : null : null}
</View>
</View>];
return <View {...props2} />;
};
@@ -0,0 +1,109 @@
// Metro module 8644 (f8645).
import { useCallback } from "react";
import { View } from "react-native";
import UserStore from "../../../../stores/UserStore";
import { createStyles } from "../../../../design/components/Styles/native/createStyles";
import Module712 from "../../../../_bundle/Module712";
import useStartAuthorize from "../../../application_account_linking/native/useStartAuthorize";
import { useStateFromStores } from "../../../../_bundle/Module589";
import { GameProfileTrackActionActions } from "../../GameProfileAnalyticUtils";
import { Text } from "../../../../design/components/Text/native/Text";
import { intl, t } from "../../../../intl/index.native";
import FastImage from "../../../../components_native/common/FastImage";
import { Avatar, AvatarSizes } from "../../../../design/void/native";
import { Button } from "../../../../design/components/Button/native/Button.native";
import { ExperimentalGameControllerLinkIcon } from "../../../../design/components/Icon/native/redesign/generated/ExperimentalGameControllerLinkIcon";
const useStyles = createStyles({
container: {
gap: Module712.space.PX_8
},
headerText: {
paddingHorizontal: Module712.space.PX_8
},
card: {
borderRadius: Module712.radii.lg,
borderWidth: 1,
borderColor: Module712.colors.BORDER_SUBTLE,
backgroundColor: Module712.colors.BACKGROUND_BASE_LOW,
padding: Module712.space.PX_16,
gap: Module712.space.PX_16
},
cardImagesContainer: {
flexDirection: "row",
gap: Module712.space.PX_8,
alignItems: "center",
alignSelf: "center"
},
ellipseGroup: {
flexDirection: "row",
justifyContent: "space-between",
gap: Module712.space.PX_4
},
ellipse: {
width: 4,
height: 4,
backgroundColor: Module712.colors.MOBILE_TEXT_HEADING_PRIMARY,
opacity: 0.3,
borderRadius: Module712.radii.round
},
cardImageApplication: {
width: 48,
height: 48,
borderRadius: Module712.radii.sm
},
cardContent: {
gap: Module712.space.PX_4,
alignSelf: "center",
flexDirection: "column",
alignItems: "center",
justifyContent: "center",
paddingHorizontal: Module712.space.PX_24
},
cardText: {
textAlign: "center"
}
});
export default function GameProfileLinkAccount(props) {
const { game, trackAction, analyticsLocations } = props;
const styles = useStyles();
const startAuthorize = useStartAuthorize(game);
const { fetched, hasAlreadyLinked, canStartAuthorization, startAuthorization, connectionApp } = startAuthorize;
const stateFromStores = useStateFromStores([UserStore], () => UserStore.getCurrentUser());
const callback = useCallback(() => {
trackAction(GameProfileTrackActionActions.LinkAccount);
startAuthorization({
analyticsLocations
});
}, [trackAction, startAuthorization, analyticsLocations]);
if (fetched && connectionApp != null && canStartAuthorization && !hasAlreadyLinked && stateFromStores != null) {
const iconSource = connectionApp.getIconSource(48);
return <View style={styles.container}>
<Text variant="heading-sm/semibold" color="mobile-text-heading-primary" style={styles.headerText}>
{intl.string(t["VDAhr+"])}
</Text>
<View style={styles.card}>
{iconSource != null ? <View style={styles.cardImagesContainer}>
<FastImage source={iconSource} style={styles.cardImageApplication} />
<View style={styles.ellipseGroup}>
<View style={styles.ellipse} />
<View style={styles.ellipse} />
<View style={styles.ellipse} />
</View>
<Avatar size={AvatarSizes.LARGE_48} user={stateFromStores} guildId={void 0} />
</View> : null}
<View style={styles.cardContent}>
<Text variant="heading-md/semibold" color="mobile-text-heading-primary" style={styles.cardText}>
{intl.formatToPlainString(t.hUbQT2, {
gameName: connectionApp.name
})}
</Text>
<Text variant="text-sm/medium" color="text-default" style={styles.cardText}>
{intl.string(t["JKqu+4"])}
</Text>
</View>
<Button variant="secondary" size="md" text={intl.string(t.jynBQ5)} onPress={callback} icon={<ExperimentalGameControllerLinkIcon size="sm" />} />
</View>
</View>;
}
return null;
};
@@ -0,0 +1,236 @@
// Metro module 8519 (f8520).
import { useRef, useCallback, useState, useEffect, useMemo } from "react";
import { Image as Image2, Pressable, ScrollView, View } from "react-native";
import { NOOP } from "../../../../_bundle/Module505";
import { createStyles } from "../../../../design/components/Styles/native/createStyles";
import Module712 from "../../../../_bundle/Module712";
import { GameProfileTrackActionActions } from "../../GameProfileAnalyticUtils";
import { openMediaModal } from "../../../media_viewer/native/components/openMediaModal";
import { createVideoControls, VideoComponent } from "../../../../components_native/common/Video";
import { isAndroid } from "../../../../_bundle/Module501";
import useWindowDimensions_native from "../../../screen/useWindowDimensions.native";
import { useObscuredSurface } from "../../../safety_common/ObscuredSurfaceContext";
import { getBestMediaProxySize, getDevicePixelRatio } from "../../../image_upload/ImageLoaderUtils";
import { getAssetURL } from "../../../../utils/StoreUtils";
import { HermesBuiltin } from "../../../../_hermes/prelude";
let width, useStyles, TrailerItem;
const ImageItem = function ImageItem(props) {
const { url, index, sources, trackAction, width: width4, height: height2, onScrollToIndex, setMediaModalOpen } = props;
const styles = useStyles();
const ref = useRef(null);
return <Pressable ref={ref} style={[styles.mediaItem, {
width: width4,
height: height2
}]} onPress={useCallback(() => {
trackAction(GameProfileTrackActionActions.ClickImage);
setMediaModalOpen(true);
openMediaModal({
initialSources: sources,
initialIndex: index,
originViewOrOriginLayout: ref.current,
analyticsSource: "game_profile",
openAs: "action-sheet",
onIndexChange: (a0) => onScrollToIndex(a0),
onClose: () => setMediaModalOpen(false)
});
}, [sources, index, trackAction, onScrollToIndex, setMediaModalOpen])}>
<Image2 source={{
uri: url
}} style={styles.mediaImage} />
</Pressable>;
};
TrailerItem = function TrailerItem(props) {
let ref4;
const { url, posterUrl, active, index: index2, sources: sources2, trackAction: trackAction2, width: width4, height: height2, onScrollToIndex: onScrollToIndex2, setMediaModalOpen: setMediaModalOpen2 } = props;
ref4 = void 0;
const styles = useStyles();
const ref2 = useRef(null);
const ref3 = useRef(0);
const [state, setState] = useState(0);
const callback2 = useCallback((a0) => {
ref3.current = a0;
}, []);
ref4 = useRef(createVideoControls(NOOP));
ref4.current.useSubscribe(callback2, NOOP, NOOP);
useEffect(() => {
if (isAndroid() && !active) {
setState((prevState) => prevState + 1);
} else {
ref4.current.seek(0);
}
}, [active]);
return <Pressable ref={ref2} style={[styles.mediaItem, {
width: width4,
height: height2
}]} onPress={useCallback(() => {
trackAction2(GameProfileTrackActionActions.ClickTrailer);
setMediaModalOpen2(true);
openMediaModal({
initialSources: sources2,
initialIndex: index2,
initialIndexVideoStartTime: ref3.current,
originViewOrOriginLayout: ref2.current,
analyticsSource: "game_profile",
openAs: "action-sheet",
onIndexChange: (a0) => onScrollToIndex2(a0),
onClose: () => setMediaModalOpen2(false)
});
}, [trackAction2, sources2, index2, onScrollToIndex2, setMediaModalOpen2])}>
<VideoComponent key={isAndroid() ? `render-${state}` : void 0} style={styles.mediaVideo} source={{
uri: url
}} poster={posterUrl} paused={!active} muted resizeMode="cover" pauseWhileAppInactive controls={ref4.current} />
</Pressable>;
};
width = 1920;
useStyles = createStyles({
container: {
gap: Module712.space.PX_12,
marginHorizontal: -Module712.space.PX_16
},
scrollView: {
flexDirection: "row",
overflow: "visible"
},
scrollViewContent: {
gap: Module712.space.PX_12,
paddingHorizontal: Module712.space.PX_16
},
mediaItem: {
maxWidth: 366,
maxHeight: 200,
borderRadius: Module712.radii.lg,
overflow: "hidden",
...Module712.shadows.SHADOW_HIGH
},
mediaImage: {
width: "100%",
height: "100%",
resizeMode: "cover"
},
mediaVideo: {
width: "100%",
height: "100%",
backgroundColor: Module712.colors.BLACK
}
});
export default function GameProfileMedia(props) {
let width3, height, memo, memo2, memo3, memo4, memo5, callback;
const { game, trackAction: trackAction3 } = props;
width3 = void 0;
height = void 0;
memo = void 0;
memo2 = void 0;
memo3 = void 0;
memo4 = void 0;
memo5 = void 0;
callback = void 0;
const styles = useStyles();
const width2 = useWindowDimensions_native().width;
const obscured = useObscuredSurface().obscured;
const [state, setState2] = useState(0);
const [state2, setState3] = useState(0);
const [state3, setState4] = useState(false);
const ref5 = useRef(null);
[width3, height] = useMemo(() => {
const bestMediaProxySize = getBestMediaProxySize(Math.min(width2, width) * getDevicePixelRatio());
return [bestMediaProxySize, bestMediaProxySize / 1.83];
}, [width2]);
const callback2 = useCallback((a0) => {
setState2(a0.nativeEvent.layout.width);
}, []);
memo = useMemo(() => {
let r10;
if (game == null) {
r10 = [];
} else {
let trailers = game.trailers;
if (trailers == null) {
trailers = [];
}
const r8 = trailers.map((trailer) => ({
type: "trailer",
url: getAssetURL(trailer.application_id, trailer.id, 1920, "mp4"),
thumbnailUrl: getAssetURL(trailer.application_id, trailer.id, Math.min(width2, width), "webp")
}));
r10 = [];
const r0 = HermesBuiltin.arraySpread(r10, r8, 0);
let screenshotUrls = game.screenshotUrls;
if (screenshotUrls == null) {
screenshotUrls = [];
}
HermesBuiltin.arraySpread(r10, screenshotUrls.map((screenshotUrl) => ({
type: "image",
url: screenshotUrl,
thumbnailUrl: screenshotUrl.replace.call(screenshotUrl, /size=\d+/g, `size=${width3}`)
})), r0);
}
return r10;
}, [game, width3, width2]);
memo2 = useMemo(() => Math.max(0, Math.min(366, state - Module712.space.PX_12 - 2 * Module712.space.PX_16)), [state]);
memo3 = useMemo(() => Math.min(200, memo2 / 1.83), [memo2]);
memo4 = useMemo(() => memo.map((item, index) => ({
uri: item.url,
videoURI: item.type === "trailer" ? item.url : void 0,
mediaIndex: index,
width,
height: 1080,
thumbnail: {
width: width3,
height,
uri: item.thumbnailUrl
},
accessoryType: "embed",
disableDownload: true
})), [memo, width3, height]);
memo5 = useMemo(() => {
let c26212_0 = (state - memo2 - 2 * Module712.space.PX_16) / 2;
let c26212_1 = memo2 + Module712.space.PX_12;
return memo.map((item, index) => Math.max(0, index * c26212_1 - c26212_0));
}, [memo, state, memo2]);
const callback3 = useCallback((a0) => {
let length;
if (memo5.length !== 0) {
const r11 = a0.nativeEvent.contentOffset.x;
const r20 = Math.abs(memo5[0] - r11);
const r6 = 1 < memo5.length;
let r2 = 1;
let r22 = r20;
let r1 = 0;
let r23 = 0;
if (r6) {
do {
const r28 = Math.abs(memo5[r2] - r11);
const r3 = r2;
let r29 = r22;
let r0 = r1;
if (r28 < r29) {
r29 = r28;
r0 = r3;
}
r2 = r3 + 1;
length = memo5.length;
r22 = r29;
r1 = r0;
r23 = r1;
} while (r2 < length);
}
setState3(r23);
}
}, [memo5]);
callback = useCallback((a0) => {
const current = ref5.current;
if (current != null) {
current.scrollTo({
x: memo5[a0],
y: 0,
animated: false
});
}
setState3(a0);
}, [memo5]);
return memo.length !== 0 ? <View style={styles.container} onLayout={callback2}>
<ScrollView ref={ref5} horizontal showsHorizontalScrollIndicator={false} style={styles.scrollView} contentContainerStyle={styles.scrollViewContent} decelerationRate="fast" snapToOffsets={memo5} snapToStart={false} snapToEnd={false} onMomentumScrollEnd={callback3}>
{memo.map((item, a1) => item.type === "trailer" ? <TrailerItem key={`${item.url}-${a1}`} url={item.url} posterUrl={item.thumbnailUrl} active={(obscured ? !obscured : !state3) && state2 === a1} index={a1} sources={memo4} trackAction={trackAction3} width={memo2} height={memo3} onScrollToIndex={callback} setMediaModalOpen={setState4} /> : <ImageItem key={`${item.url}-${a1}`} url={item.url} index={a1} sources={memo4} trackAction={trackAction3} width={memo2} height={memo3} onScrollToIndex={callback} setMediaModalOpen={setState4} />)}
</ScrollView>
</View> : null;
};
@@ -0,0 +1,119 @@
// Metro module 11946 (f11947).
import { useEffect, useMemo } from "react";
import { Image as Image2, StyleSheet, View } from "react-native";
import { createStyles } from "../../../../design/components/Styles/native/createStyles";
import Module712 from "../../../../_bundle/Module712";
import ReanimatedRexport, { useSharedValue, useAnimatedStyle } from "../../../reanimated/ReanimatedRexport";
import { withTiming } from "../../../../design/animation/reanimated/timing/timing";
import { SUPPORTS_WEBP } from "../../../../utils/AvatarUtils";
import { BackgroundBlurFill } from "../../../../design/components/experimental/native";
import { Heading } from "../../../../design/components/Text/native/Text";
import GameProfileRankPill from "./GameProfileRankPill";
const useStyles = createStyles({
headerContainer: {
height: 56,
paddingHorizontal: Module712.space.PX_16,
borderBottomWidth: StyleSheet.hairlineWidth,
borderBottomColor: Module712.colors.BORDER_SUBTLE,
overflow: "hidden",
justifyContent: "center"
},
headerRow: {
flexDirection: "row",
alignItems: "center",
gap: Module712.space.PX_8
},
icon: {
width: 32,
height: 32,
borderRadius: Module712.radii.sm
},
titleContainer: {
flex: 1,
flexDirection: "row",
alignItems: "center",
gap: Module712.space.PX_8,
minWidth: 0
},
headerRight: {
flexDirection: "row",
alignItems: "center"
},
rankPillContainer: {
flex: 1,
flexDirection: "row",
alignItems: "center"
}
});
const __initData = {
code: "function GameProfileNavigationHeaderTsx1(){const{headerRightProgress}=this.__closure;return{opacity:headerRightProgress.get()};}"
};
const __initData2 = {
code: "function GameProfileNavigationHeaderTsx2(){const{headerRightProgress}=this.__closure;return{opacity:1-headerRightProgress.get()};}"
};
export default function GameProfileNavigationHeader(props) {
const { game, application, headerRight } = props;
const styles = useStyles();
const r4 = headerRight != null;
let c19280_2 = r4;
const sharedValue = useSharedValue(r4 ? 1 : 0);
useEffect(() => {
sharedValue.set(withTiming(c19280_2 ? 1 : 0, {
duration: 200
}));
}, [r4, sharedValue]);
const x = () => ({
opacity: sharedValue.get()
});
x.__closure = {
headerRightProgress: sharedValue
};
x.__workletHash = 16001524280109;
x.__initData = __initData;
const animatedStyle = useAnimatedStyle(x);
const b = () => ({
opacity: 1 - sharedValue.get()
});
b.__closure = {
headerRightProgress: sharedValue
};
b.__workletHash = 5182160908530;
b.__initData = __initData2;
const animatedStyle2 = useAnimatedStyle(b);
const memo = useMemo(() => {
let r4 = game == null ? void 0 : game.getIconURL(32, SUPPORTS_WEBP ? "webp" : "png");
if (r4 == null) {
r4 = application == null ? void 0 : application.getIconURL(32, SUPPORTS_WEBP ? "webp" : "png");
}
if (r4 == null) {
r4 = null;
}
return r4;
}, [game, application]);
let r21 = game?.name;
if (r21 == null) {
r21 = application?.name;
}
const r55 = r21 == null;
const r56 = r55 ? null : <View style={styles.headerContainer}>
<BackgroundBlurFill />
<View style={styles.headerRow}>
{memo != null && <Image2 source={{
uri: memo
}} style={styles.icon} />}
<View style={styles.titleContainer}>
<Heading variant="redesign/heading-18/bold" color="mobile-text-heading-primary" lineClamp={1}>{r21}</Heading>
{game?.l30Rank != null && <View style={styles.rankPillContainer}>
<GameProfileRankPill rank={game.l30Rank} compact />
<ReanimatedRexport.View style={[StyleSheet.absoluteFill, animatedStyle2]}>
<GameProfileRankPill rank={game.l30Rank} />
</ReanimatedRexport.View>
</View>}
</View>
{headerRight != null && <ReanimatedRexport.View style={[styles.headerRight, animatedStyle]}>
{headerRight()}
</ReanimatedRexport.View>}
</View>
</View>;
return r56;
};
@@ -0,0 +1,39 @@
// Metro module 8518 (f8519).
import { View } from "react-native";
import { createStyles } from "../../../../design/components/Styles/native/createStyles";
import Module712 from "../../../../_bundle/Module712";
import { TrophyIcon } from "../../../../design/components/Icon/native/redesign/generated/TrophyIcon";
import { Text } from "../../../../design/components/Text/native/Text";
import { intl, t } from "../../../../intl/index.native";
const useStyles = createStyles({
container: {
flex: 1,
flexDirection: "row",
alignItems: "flex-end"
},
gameRankPill: {
flexDirection: "row",
backgroundColor: Module712.colors.WHITE,
borderRadius: Module712.radii.round,
paddingHorizontal: Module712.space.PX_8,
alignItems: "center",
gap: Module712.space.PX_4,
...Module712.shadows.SHADOW_LOW
}
});
export default function GameProfileRankPill(props) {
const { rank, compact = false } = props;
const styles = useStyles();
return <View style={styles.container}>
<View style={styles.gameRankPill}>
<TrophyIcon size="xxs" color={Module712.colors.BLACK} />
<Text variant="text-xs/bold" color="text-overlay-dark">
{(compact ? intl.formatToPlainString(t.UA6RoE, {
rank
}) : intl.formatToPlainString(t.ehZXlZ, {
rank
})).toUpperCase()}
</Text>
</View>
</View>;
};
@@ -0,0 +1,19 @@
// Metro module 11942 (f11943).
import { useCallback } from "react";
import ActionSheetActionCreators from "../../../action_sheet/native/ActionSheetActionCreators";
import { GameProfileTrackActionActions } from "../../GameProfileAnalyticUtils";
import ModalActionCreators from "../../../../actions/ModalActionCreators";
import { MODAL_KEY } from "./GameDetectionReportModal";
import { Button } from "../../../../design/components/Button/native/Button.native";
import { intl, t } from "../../../../intl/index.native";
export default function GameProfileReportButton(props) {
const { applicationId, trackAction } = props;
const callback = useCallback(() => {
ActionSheetActionCreators.hideActionSheet();
trackAction(GameProfileTrackActionActions.Feedback);
ModalActionCreators.pushLazy(import("./GameDetectionReportModal"), {
applicationId
}, MODAL_KEY);
}, [applicationId, trackAction]);
return <Button variant="secondary" size="md" text={intl.string(t.qP2cXd)} onPress={callback} />;
};
@@ -0,0 +1,227 @@
// Metro module 8521 (f8522).
import { useCallback } from "react";
import { Image as Image2, Pressable, View } from "react-native";
import { createStyles } from "../../../../design/components/Styles/native/createStyles";
import Module712 from "../../../../_bundle/Module712";
import useOpenExternalUrlFromGameProfile from "../../hooks/useOpenExternalUrlFromGameProfile";
import Linking from "../../../../lib/native/Linking";
import { calculateSteamReviewScoreDescription } from "../../../game_detection/calculateSteamReviewScoreDescription";
import * as _GameProfileReviewUtils from "../../GameProfileReviewUtils";
import { getSteamReviewScoreDescriptionColor, getSteamReviewScoreDescriptionIntl } from "../../GameProfileReviewUtils";
import { GameProfileTrackActionActions } from "../../GameProfileAnalyticUtils";
import { intl, t } from "../../../../intl/index.native";
import { SteamNeutralIcon } from "../../../../design/components/Icon/native/redesign/generated/SteamNeutralIcon";
import { Text } from "../../../../design/components/Text/native/Text";
import { SteamReviewScoreDescription } from "../../../game_detection/GameDetectionTypes";
import { getOpenCriticTierText, getOpenCriticCircleRatingColor, getOpenCriticTierImage } from "../../hooks/useGameProfileOpenCritic";
import OpenCriticRatingCircle from "./OpenCriticRatingCircle";
import { useSteamWebsiteUrl } from "../../hooks/useSteamWebsiteUrl";
import { SteamReleaseStatus } from "../../../../_bundle/Module8492";
let useStyles, OpenCriticReview;
const SteamReviewRow = function SteamReviewRow(props) {
const url = props.url;
let showBorderBottom = props.showBorderBottom;
const { trackAction, title, rating, ratingCount, isRecentRating } = props;
const styles = useStyles();
const openExternalUrlFromGameProfile = useOpenExternalUrlFromGameProfile(Linking.openURL);
let c16625_2 = openExternalUrlFromGameProfile;
const r11 = calculateSteamReviewScoreDescription(rating, ratingCount, isRecentRating);
const steamReviewScoreDescriptionColor = getSteamReviewScoreDescriptionColor(r11);
const props2 = {
onPress: useCallback(() => {
trackAction(GameProfileTrackActionActions.SteamReviews);
c16625_2(url);
}, [openExternalUrlFromGameProfile, url, trackAction]),
accessibilityRole: "link",
accessibilityLabel: intl.string(t.YNC5Di),
style: null,
children: null
};
const style = [styles.reviewRow, ,];
if (showBorderBottom) {
showBorderBottom = styles.reviewRowNotLast;
}
style[1] = showBorderBottom;
props2.style = style;
props2.children = [<View style={styles.steamNameContainer}>
<SteamNeutralIcon size="sm" color={Module712.colors.ICON_STRONG} />
<Text variant="heading-sm/medium" color="mobile-text-heading-primary">{title}</Text>
</View>, <View style={styles.steamRatingContainer}>
<Text variant="text-sm/medium" color={steamReviewScoreDescriptionColor}>
{getSteamReviewScoreDescriptionIntl(r11)}
</Text>
{ratingCount != null && r11 !== SteamReviewScoreDescription.NO_USER_REVIEWS && <Text variant="text-sm/medium" color="text-subtle">
{intl.format(t.sgIoin, {
rating_count: ratingCount.toLocaleString()
}).toString()}
</Text>}
</View>];
return <Pressable {...props2} />;
};
OpenCriticReview = function OpenCriticReview(props) {
const { game, url: url2, trackAction: trackAction2 } = props;
const styles = useStyles();
let r30 = game.reviews?.opencritic;
if (r30 == null) {
r30 = {
topCriticRating: void 0,
topCriticRatingCount: void 0,
tier: void 0
};
}
const tier = r30.tier;
let topCriticRating = r30.topCriticRating;
if (topCriticRating == null) {
topCriticRating = -1;
}
let topCriticRatingCount = r30.topCriticRatingCount;
if (topCriticRatingCount == null) {
topCriticRatingCount = -1;
}
const openExternalUrlFromGameProfile = useOpenExternalUrlFromGameProfile(Linking.openURL);
let c16626_2 = openExternalUrlFromGameProfile;
const callback = useCallback(() => {
trackAction2(GameProfileTrackActionActions.OpenCriticReviews);
c16626_2(url2);
}, [openExternalUrlFromGameProfile, url2, trackAction2]);
const accessibilityLabel = tier != null ? getOpenCriticTierText(tier) : "";
const r45 = tier != null ? getOpenCriticCircleRatingColor(tier) : {
foregroundColor: "",
backgroundColor: ""
};
const { foregroundColor, backgroundColor } = r45;
const props2 = {
onPress: callback,
accessibilityRole: "link",
accessibilityLabel: intl.string(t.aLNBAw),
style: styles.reviewRow,
children: null
};
const children = [<Text variant="heading-sm/medium" color="mobile-text-heading-primary">
{intl.string(t["UxvER+"])}
</Text>, ,];
const r89 = [tier != null ? <View style={styles.opencriticTopCriticContainer} accessibilityLabel={accessibilityLabel} accessibilityRole="image">
<Image2 source={{
uri: getOpenCriticTierImage(tier)
}} style={styles.opencriticTopCriticImage} accessible accessibilityLabel={accessibilityLabel} />
</View> : null, tier != null ? topCriticRating > 0 ? topCriticRatingCount > 0 ? <View style={[styles.opencriticTopCriticContainer, {
backgroundColor
}]} accessibilityLabel={intl.string(t.Ub4YR1)} accessibilityRole="image">
<OpenCriticRatingCircle rating={topCriticRating} strokeColor={foregroundColor} size={32} />
<View style={styles.opencriticTopCriticRatingContainer}>
<Text variant="text-xs/bold" color="text-overlay-light">
{Math.floor(topCriticRating)}
</Text>
</View>
</View> : null : null : null, topCriticRating <= 0 ? tier == null ? <Text variant="text-xs/medium" color={getSteamReviewScoreDescriptionColor(SteamReviewScoreDescription.NO_USER_REVIEWS)}>
{intl.string(t["0xYzpO"])}
</Text> : null : topCriticRatingCount <= 0 ? tier == null ? <Text variant="text-xs/medium" color={getSteamReviewScoreDescriptionColor(SteamReviewScoreDescription.NO_USER_REVIEWS)}>
{intl.string(t["0xYzpO"])}
</Text> : null : null];
children[1] = <View style={styles.opencriticRightContainer}>{r89}</View>;
props2.children = children;
return <Pressable {...props2} />;
};
useStyles = createStyles({
container: {
gap: Module712.space.PX_8
},
headerText: {
paddingHorizontal: Module712.space.PX_8
},
reviewContainer: {
borderRadius: Module712.radii.lg,
borderWidth: 1,
borderColor: Module712.colors.BORDER_SUBTLE,
overflow: "hidden"
},
reviewRow: {
height: 56,
flexDirection: "row",
alignItems: "center",
justifyContent: "space-between",
padding: Module712.space.PX_12
},
reviewRowNotLast: {
borderBottomWidth: 1,
borderBottomColor: Module712.colors.BACKGROUND_MOD_SUBTLE
},
steamNameContainer: {
flexDirection: "row",
alignItems: "center",
gap: Module712.space.PX_8
},
steamRatingContainer: {
flexDirection: "row",
alignItems: "flex-end",
flexShrink: 1,
paddingLeft: Module712.space.PX_32,
gap: Module712.space.PX_4
},
opencriticRightContainer: {
flexDirection: "row",
alignItems: "center",
gap: Module712.space.PX_12
},
opencriticTopCriticContainer: {
width: 32,
height: 32,
borderRadius: Module712.radii.round,
backgroundColor: Module712.colors.BACKGROUND_SURFACE_HIGH,
alignItems: "center",
justifyContent: "center"
},
opencriticTopCriticImage: {
width: 32,
height: 32
},
opencriticTopCriticRatingContainer: {
position: "absolute",
top: 0,
left: 1,
right: 0,
bottom: 0,
alignItems: "center",
justifyContent: "center"
}
});
export default function GameProfileReviews(props) {
let r68;
const { game, trackAction: trackAction3 } = props;
const styles = useStyles();
const steamWebsiteUrl = useSteamWebsiteUrl(game?.id);
const opencriticUrl = game?.opencriticUrl;
if (game == null) {
return null;
}
const r4 = game.steamReleaseStatus !== SteamReleaseStatus.RETIRED_ABANDONED && steamWebsiteUrl != null;
const steam = game.reviews?.steam;
const r48 = calculateSteamReviewScoreDescription(steam?.recentRating, steam?.recentRatingCount, true);
const r3 = r4 ? r48 !== SteamReviewScoreDescription.NO_USER_REVIEWS : r4;
const canShowLocalizedSteamReview = _GameProfileReviewUtils.canShowLocalizedSteamReview(steam);
const r57 = steam == null;
const rating = canShowLocalizedSteamReview ? r57 ? void 0 : steam.localizedRating : r57 ? void 0 : steam.rating;
const r59 = steam == null;
const ratingCount = canShowLocalizedSteamReview ? r59 ? void 0 : steam.localizedRatingCount : r59 ? void 0 : steam.ratingCount;
const r25 = canShowLocalizedSteamReview ? t["aWb+V4"] : t["8e4LiB"];
const showBorderBottom = game.reviews?.opencritic != null && opencriticUrl != null;
L55: {
if (!r4 && !r3) {
r68 = null;
if (!showBorderBottom) {
break L55;
}
}
r68 = <View style={styles.container}>
<Text variant="heading-sm/semibold" color="mobile-text-heading-primary" style={styles.headerText}>
{intl.string(t.GaAQXP)}
</Text>
<View style={styles.reviewContainer}>
{r3 ? steamWebsiteUrl != null ? <SteamReviewRow url={steamWebsiteUrl} showBorderBottom={r4 || showBorderBottom} trackAction={trackAction3} title={intl.string(t.MQGNsN)} rating={steam?.recentRating} ratingCount={steam?.recentRatingCount} isRecentRating /> : null : null}
{r4 ? steamWebsiteUrl != null ? <SteamReviewRow url={steamWebsiteUrl} showBorderBottom={showBorderBottom} trackAction={trackAction3} title={intl.string(r25)} rating={rating} ratingCount={ratingCount} isRecentRating={false} /> : null : null}
{showBorderBottom ? opencriticUrl != null ? <OpenCriticReview game={game} url={opencriticUrl} trackAction={trackAction3} /> : null : null}
</View>
</View>;
}
return r68;
};
@@ -0,0 +1,297 @@
// Metro module 8481 (f8482).
import { useState, useRef, useCallback, useMemo, useEffect } from "react";
import { ActivityIndicator, View } from "react-native";
import GameProfileStore from "../../GameProfileStore";
import { createStyles } from "../../../../design/components/Styles/native/createStyles";
import Module712 from "../../../../_bundle/Module712";
import { Button } from "../../../../design/components/Button/native/Button.native";
import { intl, t } from "../../../../intl/index.native";
import { useBottomSheetRef } from "../../../../design/components/Sheet/native/useBottomSheetRef";
import useOpenExternalUrlFromGameProfile from "../../hooks/useOpenExternalUrlFromGameProfile";
import Linking from "../../../../lib/native/Linking";
import { generateViewId, getGuildIdAndVerifiedFromInvite, trackGameProfileAction, trackGameProfileOpen, GameProfileTypes, trackGameProfileClose } from "../../GameProfileAnalyticUtils";
import { useGame } from "../../../games/hooks/useGame";
import useGameProfileObscured from "../../hooks/useGameProfileObscured";
import * as _ReanimatedRexport from "../../../reanimated/ReanimatedRexport";
import ReanimatedRexport, { useSharedValue, useAnimatedReaction, useAnimatedStyle } from "../../../reanimated/ReanimatedRexport";
import useInAppBrowserReturn from "../hooks/useInAppBrowserReturn";
import * as _timing from "../../../../design/animation/reanimated/timing/timing";
import { useGameProfileStoreWebsites } from "../../hooks/useGameProfileStoreWebsites";
import getGameProfileStoreWebsiteData from "../utils/getGameProfileStoreWebsiteData";
import ActionSheetActionCreators, { showActionSheet } from "../../../action_sheet/native/ActionSheetActionCreators";
import GameProfileStoreLinksActionSheet, { ACTION_SHEET_KEY } from "./GameProfileStoreLinksActionSheet";
import { GameProfileSimilarGamesMobileExperiment } from "../../SimilarGamesExperiments";
import { BottomSheet } from "../../../../design/components/Sheet/native/BottomSheet.native";
import { BottomSheetScrollView } from "../../../../_bundle/Module5245";
import ObscuredSurface from "../../../safety_common/native/ObscuredSurface";
import GameProfileView from "./GameProfileView";
import GameProfileNavigationHeader from "./GameProfileNavigationHeader";
import { ActionSheetHeaderBar } from "../../../../design/components/Sheet/native/ActionSheetHeaderBar.native";
let useStyles, __initData, __initData2, __initData3, __initData4, __initData5;
const GetButton = function GetButton(props) {
const onPress = props.onPress;
return <Button variant="primary" size="sm" text={intl.string(t.l8JeHg)} onPress={onPress} accessibilityLabel={intl.string(t.Vsxqmz)} />;
};
useStyles = createStyles({
loadingContainer: {
flex: 1,
justifyContent: "center",
alignItems: "center",
minHeight: 300,
backgroundColor: Module712.colors.BACKGROUND_BASE_LOWEST
},
scrollView: {
flex: 1,
backgroundColor: Module712.colors.BACKGROUND_BASE_LOWEST
},
stickyHeader: {
position: "absolute",
top: 0,
left: 0,
right: 0
}
});
__initData = {
code: "function GameProfileScreenTsx1(){const{heroHeaderHeight,scrollY,STICKY_HEADER_HEIGHT}=this.__closure;return heroHeaderHeight.get()>0&&scrollY.get()>=heroHeaderHeight.get()-STICKY_HEADER_HEIGHT;}"
};
__initData2 = {
code: "function GameProfileScreenTsx2(isVisible,wasVisible){const{stickyHeaderVisible,withTiming}=this.__closure;if(isVisible!==wasVisible){stickyHeaderVisible.set(withTiming(isVisible?1:0,{duration:150}));}}"
};
__initData3 = {
code: "function GameProfileScreenTsx3(){const{interpolate,stickyHeaderVisible,STICKY_HEADER_HEIGHT}=this.__closure;return{transform:[{translateY:interpolate(stickyHeaderVisible.get(),[0,1],[-1*STICKY_HEADER_HEIGHT,0])}]};}"
};
__initData4 = {
code: "function GameProfileScreenTsx4(){const{scrollY,storeLinksSectionBottomY,STICKY_HEADER_HEIGHT}=this.__closure;return scrollY.get()>storeLinksSectionBottomY.get()-STICKY_HEADER_HEIGHT;}"
};
__initData5 = {
code: "function GameProfileScreenTsx5(shouldShow,prevShouldShow){const{runOnJS,setShowGetButton}=this.__closure;if(shouldShow!==prevShouldShow){runOnJS(setShowGetButton)(shouldShow);}}"
};
export default function GameProfileScreen(props) {
let ref, ref2, state2, name, sharedValue, ref3, sharedValue2, sharedValue3, sharedValue4, state3, setState, gameProfileStoreWebsites, memo, ref4, ref5, callback, callback2;
const { gameId, source, sourceUserId, initialScrollOffset = 0 } = props;
let c16611_3 = initialScrollOffset;
ref = void 0;
ref2 = void 0;
state2 = void 0;
name = void 0;
sharedValue = void 0;
ref3 = void 0;
sharedValue2 = void 0;
sharedValue3 = void 0;
sharedValue4 = void 0;
state3 = void 0;
setState = void 0;
gameProfileStoreWebsites = void 0;
memo = void 0;
ref4 = void 0;
ref5 = void 0;
callback = void 0;
callback2 = void 0;
const styles = useStyles();
const bottomSheetRef2 = useBottomSheetRef();
const { bottomSheetRef, bottomSheetClose } = bottomSheetRef2;
const openExternalUrlFromGameProfile = useOpenExternalUrlFromGameProfile(Linking.openURL);
let c16611_4 = openExternalUrlFromGameProfile;
const [state] = useState(() => generateViewId());
ref = useRef(null);
ref2 = useRef(0);
const game = useGame(gameId);
const { data, isLoading } = game;
const gameProfileObscured = useGameProfileObscured(data);
let onGuildInviteResolved;
[state2, onGuildInviteResolved] = useState(null);
name = data?.name;
sharedValue = useSharedValue(0);
const callback3 = useCallback((a0) => {
const current = a0.nativeEvent.contentOffset.y;
sharedValue.set(current);
ref2.current = current;
}, [sharedValue]);
ref3 = useRef(false);
const callback4 = useCallback(() => {
if (c16611_3 > 0 && !ref3.current) {
ref3.current = true;
const current = ref.current;
if (current != null) {
current.scrollTo({
y: c16611_3,
animated: false
});
}
}
}, [initialScrollOffset]);
useInAppBrowserReturn({
gameId: data?.id,
scrollOffsetRef: ref2
});
sharedValue2 = useSharedValue(0);
sharedValue3 = useSharedValue(0);
const U = () => sharedValue2.get() > 0 && sharedValue.get() >= sharedValue2.get() - 56;
U.__closure = {
heroHeaderHeight: sharedValue2,
scrollY: sharedValue,
STICKY_HEADER_HEIGHT: 56
};
U.__workletHash = 15395308691297;
U.__initData = __initData;
const j = function j(a0, a1) {
if (a0 !== a1) {
sharedValue3.set(_timing.withTiming(a0 ? 1 : 0, {
duration: 150
}));
}
};
j.__closure = {
stickyHeaderVisible: sharedValue3,
withTiming: _timing.withTiming
};
j.__workletHash = 3161097061646;
j.__initData = __initData2;
useAnimatedReaction(U, j);
const q = function q() {
return {
transform: [{
translateY: _ReanimatedRexport.interpolate(sharedValue3.get(), [0, 1], [-56, 0])
}]
};
};
q.__closure = {
interpolate: _ReanimatedRexport.interpolate,
stickyHeaderVisible: sharedValue3,
STICKY_HEADER_HEIGHT: 56
};
q.__workletHash = 16452163547712;
q.__initData = __initData3;
const animatedStyle = useAnimatedStyle(q);
sharedValue4 = useSharedValue(Infinity);
[state3, setState] = useState(false);
const X = () => sharedValue.get() > sharedValue4.get() - 56;
X.__closure = {
scrollY: sharedValue,
storeLinksSectionBottomY: sharedValue4,
STICKY_HEADER_HEIGHT: 56
};
X.__workletHash = 14521195063038;
X.__initData = __initData4;
const Q = function Q(a0, a1) {
if (a0 !== a1) {
_ReanimatedRexport.runOnJS(setState)(a0);
}
};
Q.__closure = {
runOnJS: _ReanimatedRexport.runOnJS,
setShowGetButton: setState
};
Q.__workletHash = 15045914286853;
Q.__initData = __initData5;
useAnimatedReaction(X, Q);
gameProfileStoreWebsites = useGameProfileStoreWebsites(data);
memo = useMemo(() => gameProfileStoreWebsites.map(getGameProfileStoreWebsiteData).filter((item) => item != null), [gameProfileStoreWebsites]);
ref4 = useRef(void 0);
ref5 = useRef(null);
useEffect(() => {
ref4.current = name;
}, [name]);
useEffect(() => {
ref5.current = state2;
}, [state2]);
callback = useCallback((a0, a1) => {
const guildIdAndVerifiedFromInvite = getGuildIdAndVerifiedFromInvite(ref5.current);
const { guildId, isVerified } = guildIdAndVerifiedFromInvite;
let current = ref4.current;
if (current == null) {
current = "";
}
trackGameProfileAction({
gameName: current,
gameId,
action: a0,
similarGameId: a1,
viewId: state,
guildId,
isVerified,
source
});
}, [gameId, state, source]);
callback2 = useCallback(() => {
if (memo.length === 1) {
const [r31] = memo;
callback(r31.action);
c16611_4(r31.url);
} else if (memo.length > 1) {
let current = ref4.current;
if (current == null) {
current = "";
}
showActionSheet({
key: ACTION_SHEET_KEY,
content: <GameProfileStoreLinksActionSheet gameName={current} websiteButtons={memo} trackAction={callback} />,
stackingBehavior: "stack"
});
}
}, [memo, callback, openExternalUrlFromGameProfile]);
useEffect(() => {
let current = ref4.current;
if (current == null) {
current = "";
}
trackGameProfileOpen({
source,
viewId: state,
gameId,
gameName: current,
authorId: sourceUserId,
profileType: GameProfileTypes.FullProfile
});
}, [gameId, source, sourceUserId, state]);
useEffect(() => () => {
let similarGames;
const guildIdAndVerifiedFromInvite = getGuildIdAndVerifiedFromInvite(ref5.current);
const { guildId, isVerified } = guildIdAndVerifiedFromInvite;
const enabled = GameProfileSimilarGamesMobileExperiment.getConfig({
location: "GameProfileScreenClose"
}).enabled;
let current = ref4.current;
if (current == null) {
current = "";
}
if (enabled) {
let r34 = GameProfileStore.getSimilarGames(gameId);
if (r34 == null) {
r34 = [];
}
similarGames = r34;
} else {
similarGames = [];
}
trackGameProfileClose({
viewId: state,
gameId,
gameName: current,
playedFriendIds: [],
playedFriendsData: [],
similarGames,
guildId,
isVerified
});
}, [gameId, source, sourceUserId, state]);
const callback5 = useCallback((a0) => {
sharedValue2.set(a0);
}, [sharedValue2]);
const callback6 = useCallback((a0) => {
sharedValue4.set(a0);
}, [sharedValue4]);
return <BottomSheet ref={bottomSheetRef} startExpanded scrollable handleDisabled onExpand={callback4}>
{!isLoading && data != null ? <BottomSheetScrollView ref={ref} style={styles.scrollView} onScroll={callback3}>
<ObscuredSurface obscured={gameProfileObscured}>
<GameProfileView game={data} invite={state2} viewId={state} source={source} trackAction={callback} onGuildInviteResolved={onGuildInviteResolved} closeModal={() => ActionSheetActionCreators.hideAllActionSheets()} scrollY={sharedValue} websiteButtons={memo} onStoreLinksMeasured={callback6} onHeaderHeightMeasured={callback5} scrollOffsetRef={ref2} />
</ObscuredSurface>
</BottomSheetScrollView> : <View style={styles.loadingContainer}>
<ActivityIndicator animating size="large" />
</View>}
<ReanimatedRexport.View style={[styles.stickyHeader, animatedStyle]} pointerEvents="box-none">
<GameProfileNavigationHeader game={data} headerRight={useMemo(() => memo.length > 0 ? state3 ? () => <GetButton onPress={callback2} /> : void 0 : void 0, [memo, state3, callback2])} />
</ReanimatedRexport.View>
<ActionSheetHeaderBar variant="overlay" onPress={bottomSheetClose} />
</BottomSheet>;
};
@@ -0,0 +1,82 @@
// Metro module 8659 (f8660).
import { useCallback } from "react";
import { View } from "react-native";
import CollectiblesCategoryStore from "../../../collectibles/CollectiblesCategoryStore";
import { createStyles } from "../../../../design/components/Styles/native/createStyles";
import Module712 from "../../../../_bundle/Module712";
import CollectiblesShopCardV2, { COLLECTIBLES_SHOP_CARD_GAP, COLLECTIBLES_SHOP_CARD_WIDTH } from "../../../collectibles/native/CollectiblesShopCardV2";
import { useGameProfileShopCollection } from "../../hooks/useGameProfileShopCollection";
import { useFetchCollectiblesProducts } from "../../../collectibles/hooks/useFetchCollectiblesProducts";
import { useStateFromStoresArray } from "../../../../_bundle/defaultAreStatesEqual";
import { GameProfileTrackActionActions } from "../../GameProfileAnalyticUtils";
import { openCollectiblesShop } from "../../../collectibles/CollectiblesActionCreators";
import AnalyticsLocation from "../../../app_analytics/AnalyticsLocation";
import { Text } from "../../../../design/components/Text/native/Text";
import { intl, t } from "../../../../intl/index.native";
import { Button } from "../../../../design/components/Button/native/Button.native";
import { ChevronSmallRightIcon } from "../../../../design/components/Icon/native/redesign/generated/ChevronSmallRightIcon";
import { FlashList } from "../../../../_bundle/noop_6676";
let useStyles, GameProfileShopCarouselContent;
const HorizontalSpacing = function HorizontalSpacing() {
return <View style={{
width: COLLECTIBLES_SHOP_CARD_GAP
}} />;
};
GameProfileShopCarouselContent = function GameProfileShopCarouselContent(props) {
const { collectionId, closeModal, trackAction } = props;
const styles = useStyles();
const gameProfileShopCollection = useGameProfileShopCollection(collectionId);
useFetchCollectiblesProducts(gameProfileShopCollection);
const stateFromStoresArray = useStateFromStoresArray([CollectiblesCategoryStore], () => gameProfileShopCollection.map((item) => CollectiblesCategoryStore.getProduct(item)).filter((item) => item != null));
const callback = useCallback(() => {
trackAction(GameProfileTrackActionActions.DiscordCollectiblesShop);
closeModal();
openCollectiblesShop({
analyticsLocations: [AnalyticsLocation.GAME_PROFILE],
analyticsSource: AnalyticsLocation.GAME_PROFILE
});
}, [trackAction, closeModal]);
return stateFromStoresArray.length !== 0 ? <View style={styles.container}>
<View style={styles.header}>
<Text variant="heading-sm/semibold" color="mobile-text-heading-primary">
{intl.string(t["5DYPT8"])}
</Text>
<Button text={intl.string(t.budhsM)} variant="tertiary" size="sm" icon={<ChevronSmallRightIcon size="sm" />} iconPosition="end" onPress={callback} />
</View>
<FlashList key={collectionId} horizontal data={stateFromStoresArray} renderItem={({ item }) => <CollectiblesShopCardV2 solidBackground cardStyle={styles.card} product={item} hideWishlistButton hidePrice onPress={() => {
trackAction(GameProfileTrackActionActions.DiscordCollectiblesShop);
closeModal();
openCollectiblesShop({
analyticsLocations: [AnalyticsLocation.GAME_PROFILE],
analyticsSource: AnalyticsLocation.GAME_PROFILE,
initialProductSkuId: item.skuId
});
}} />} showsHorizontalScrollIndicator={false} ItemSeparatorComponent={HorizontalSpacing} ListHeaderComponent={HorizontalSpacing} ListFooterComponent={HorizontalSpacing} decelerationRate="fast" snapToInterval={COLLECTIBLES_SHOP_CARD_WIDTH + COLLECTIBLES_SHOP_CARD_GAP} />
</View> : null;
};
useStyles = createStyles({
container: {
gap: Module712.space.PX_8,
marginHorizontal: -1 * Module712.space.PX_16
},
header: {
flexDirection: "row",
alignItems: "center",
justifyContent: "space-between",
paddingHorizontal: Module712.space.PX_8,
marginHorizontal: Module712.space.PX_16
},
card: {
borderRadius: Module712.radii.lg
}
});
export default function GameProfileShopCarousel(props) {
const { game, closeModal: closeModal2, trackAction: trackAction2 } = props;
const r1 = game == null;
let collectionId = void 0;
if (!r1) {
const shopCollectionIds = game.shopCollectionIds;
collectionId = shopCollectionIds == null ? void 0 : shopCollectionIds[0];
}
return collectionId == null ? null : <GameProfileShopCarouselContent collectionId={collectionId} closeModal={closeModal2} trackAction={trackAction2} />;
};
@@ -0,0 +1,137 @@
// Metro module 11922 (f11923).
import { useCallback } from "react";
import { Image as Image2, Pressable, View } from "react-native";
import Module712 from "../../../../_bundle/Module712";
import { createStyles } from "../../../../design/components/Styles/native/createStyles";
import useShouldOpenGameProfileModal from "../../hooks/useShouldOpenGameProfileModal";
import { GameProfileSources, GameProfileTrackActionActions } from "../../GameProfileAnalyticUtils";
import GameProfileActionCreators_native from "../../GameProfileActionCreators.native";
import { intl, t } from "../../../../intl/index.native";
import { Text } from "../../../../design/components/Text/native/Text";
import { GameProfileSimilarGamesMobileExperiment } from "../../SimilarGamesExperiments";
import useSimilarGames from "../../hooks/useSimilarGames";
import useWindowDimensions_native from "../../../screen/useWindowDimensions.native";
import { FlashList } from "../../../../_bundle/noop_6676";
let PX_12, PX_16, PX_122, useStyles, ListPadding, SimilarGameCard, LoadingCard;
const Spacer = function Spacer() {
return <View style={{
width: PX_12
}} />;
};
ListPadding = function ListPadding() {
return <View style={{
width: Module712.space.PX_16
}} />;
};
SimilarGameCard = function SimilarGameCard(props) {
const { game, trackAction, cardWidth: cardWidth2 } = props;
const styles = useStyles();
const height = 1.34 * cardWidth2;
const coverURL = game.getCoverURL(Math.ceil(height));
const r10 = {
width: cardWidth2,
height
};
const shouldOpenGameProfileModal = useShouldOpenGameProfileModal({
gameId: game.id,
source: GameProfileSources.SimilarGames
});
const { shouldOpenGameProfile, gameId } = shouldOpenGameProfileModal;
return <Pressable style={[styles.card, {
width: cardWidth2
}]} onPress={useCallback(() => {
trackAction(GameProfileTrackActionActions.ClickSimilarGame, game.id);
let r14 = shouldOpenGameProfile;
if (shouldOpenGameProfile) {
r14 = gameId != null;
}
if (r14) {
GameProfileActionCreators_native.openGameProfileModal({
gameId,
gameProfileModalChecks: {
shouldOpenGameProfile: true,
gameId
},
source: GameProfileSources.SimilarGames
});
}
}, [game.id, trackAction, shouldOpenGameProfile, gameId])} accessibilityRole="button" accessibilityLabel={intl.formatToPlainString(t["8QLQB+"], {
gameName: game.name
})}>
{coverURL != null ? <Image2 source={{
uri: coverURL
}} style={[styles.coverArt, r10]} /> : <View style={[styles.coverArtFallback, r10]}>
<Text variant="text-xs/medium" color="text-overlay-light" lineClamp={3}>{game.name}</Text>
</View>}
</Pressable>;
};
LoadingCard = function LoadingCard(props) {
const cardWidth2 = props.cardWidth;
return <View style={{
width: cardWidth2
}}>
<View style={[useStyles().loadingArt, {
width: cardWidth2,
height: 1.34 * cardWidth2
}]} />
</View>;
};
PX_12 = Module712.space.PX_12;
PX_16 = Module712.space.PX_16;
PX_122 = Module712.space.PX_12;
useStyles = createStyles({
container: {
gap: Module712.space.PX_8,
marginHorizontal: -1 * Module712.space.PX_16
},
header: {
paddingHorizontal: Module712.space.PX_16
},
card: {
gap: Module712.space.PX_4
},
coverArt: {
borderRadius: Module712.radii.sm
},
coverArtFallback: {
borderRadius: Module712.radii.sm,
backgroundColor: Module712.colors.BACKGROUND_SURFACE_HIGH,
justifyContent: "center",
alignItems: "center",
padding: Module712.space.PX_8
},
loadingArt: {
borderRadius: Module712.radii.sm,
backgroundColor: Module712.colors.BACKGROUND_SURFACE_HIGH
}
});
export default function GameProfileSimilarGames(props) {
const { gameId: gameId2, trackAction: trackAction2 } = props;
const styles = useStyles();
const config = GameProfileSimilarGamesMobileExperiment.useConfig({
location: "GameProfileSimilarGames"
});
const { enabled, dense } = config;
const similarGames2 = useSimilarGames(gameId2, enabled);
const { isFetching, similarGames } = similarGames2;
const length = dense ? 4 : 3;
const cardWidth = (useWindowDimensions_native().width - 2 * PX_16 - (length - 1) * PX_12 - PX_122) / length;
const data = Array.from({
length
}, (a0, a1) => a1);
return isFetching ? <View style={styles.container}>
<View style={styles.header}>
<Text variant="heading-sm/semibold" color="mobile-text-heading-primary">
{intl.string(t["6rLyQB"])}
</Text>
</View>
<FlashList horizontal data={data} renderItem={() => <LoadingCard cardWidth={cardWidth} />} showsHorizontalScrollIndicator={false} ItemSeparatorComponent={Spacer} ListHeaderComponent={ListPadding} ListFooterComponent={ListPadding} />
</View> : similarGames.length !== 0 ? <View style={styles.container}>
<View style={styles.header}>
<Text variant="heading-sm/semibold" color="mobile-text-heading-primary">
{intl.string(t["6rLyQB"])}
</Text>
</View>
<FlashList horizontal data={similarGames} renderItem={(info) => <SimilarGameCard game={info.item} trackAction={trackAction2} cardWidth={cardWidth} />} showsHorizontalScrollIndicator={false} ItemSeparatorComponent={Spacer} ListHeaderComponent={ListPadding} ListFooterComponent={ListPadding} decelerationRate="fast" snapToInterval={cardWidth + PX_12} />
</View> : null;
};
@@ -0,0 +1,51 @@
// Metro module 8520 (f8521).
import { View } from "react-native";
import { createStyles } from "../../../../design/components/Styles/native/createStyles";
import Module712 from "../../../../_bundle/Module712";
import useOpenExternalUrlFromGameProfile from "../../hooks/useOpenExternalUrlFromGameProfile";
import Linking from "../../../../lib/native/Linking";
import { Button } from "../../../../design/components/Button/native/Button.native";
import { intl, t } from "../../../../intl/index.native";
import { showActionSheet } from "../../../action_sheet/native/ActionSheetActionCreators";
import GameProfileStoreLinksActionSheet, { ACTION_SHEET_KEY } from "./GameProfileStoreLinksActionSheet";
import { GameProfileTrackActionActions } from "../../GameProfileAnalyticUtils";
let useStyles;
const WebsiteGameStoreLinkButton = function WebsiteGameStoreLinkButton(props) {
const { data, trackAction } = props;
let c16623_2 = useOpenExternalUrlFromGameProfile(Linking.openURL);
return <Button variant="secondary" size="md" text={data.title} icon={data.icon} onPress={() => {
trackAction(data.action);
c16623_2(data.url);
}} />;
};
useStyles = createStyles({
container: {
flexDirection: "column",
gap: Module712.space.PX_8
}
});
export default function GameProfileStoreLinks(props) {
const { game, trackAction: trackAction2, websiteButtons } = props;
const styles = useStyles();
const name = game?.name;
if (websiteButtons.length !== 0 && name != null) {
if (websiteButtons.length === 1) {
return <WebsiteGameStoreLinkButton data={websiteButtons[0]} trackAction={trackAction2} />;
}
if (websiteButtons.length === 2) {
return <View style={styles.container}>
<WebsiteGameStoreLinkButton data={websiteButtons[0]} trackAction={trackAction2} />
<WebsiteGameStoreLinkButton data={websiteButtons[1]} trackAction={trackAction2} />
</View>;
}
const r35 = <Button variant="secondary" size="md" text={intl.string(t["/hMurx"])} onPress={() => showActionSheet({
key: ACTION_SHEET_KEY,
content: <GameProfileStoreLinksActionSheet gameName={name} websiteButtons={websiteButtons} trackAction={trackAction2} />
})} />;
return websiteButtons[0]?.action === GameProfileTrackActionActions.XboxGamePassStoreLink ? <View style={styles.container}>
<WebsiteGameStoreLinkButton data={websiteButtons[0]} trackAction={trackAction2} />
{r35}
</View> : r35;
}
return null;
};
@@ -0,0 +1,56 @@
// Metro module 8511 (f8512).
import { View } from "react-native";
import { createStyles } from "../../../../design/components/Styles/native/createStyles";
import Module712 from "../../../../_bundle/Module712";
import useOpenExternalUrlFromGameProfile from "../../hooks/useOpenExternalUrlFromGameProfile";
import Linking from "../../../../lib/native/Linking";
import useSafeAreaInsets_native from "../../../safe_area/useSafeAreaInsets.native";
import { ActionSheet } from "../../../../design/components/Sheet/native/ActionSheet.native";
import { BottomSheetScrollView } from "../../../../_bundle/Module5245";
import { Text } from "../../../../design/components/Text/native/Text";
import { intl, t } from "../../../../intl/index.native";
import { Button } from "../../../../design/components/Button/native/Button.native";
import ActionSheetActionCreators from "../../../action_sheet/native/ActionSheetActionCreators";
const useStyles = createStyles({
header: {
gap: Module712.space.PX_8,
paddingTop: Module712.space.PX_8,
paddingHorizontal: Module712.space.PX_16,
paddingBottom: Module712.space.PX_24
},
headerText: {
textAlign: "center"
},
buttons: {
gap: Module712.space.PX_12
}
});
export default function GameProfileStoreLinksActionSheet(props) {
const { gameName, websiteButtons, trackAction } = props;
const styles = useStyles();
let c16617_1 = useOpenExternalUrlFromGameProfile(Linking.openURL);
return <ActionSheet>
<BottomSheetScrollView contentContainerStyle={{
paddingBottom: useSafeAreaInsets_native().bottom + Module712.space.PX_16
}}>
<View style={styles.header}>
<Text variant="heading-lg/semibold" color="mobile-text-heading-primary" style={styles.headerText}>
{intl.string(t["/4gj6r"])}
</Text>
<Text variant="text-md/medium" color="text-subtle" style={styles.headerText}>
{intl.format(t["0acM2Y"], {
gameName
})}
</Text>
</View>
<View style={styles.buttons}>
{websiteButtons.map(({ icon, title, url, action }) => <Button key={url} icon={icon} text={title} variant="secondary" size="md" onPress={() => {
ActionSheetActionCreators.hideActionSheet();
trackAction(action);
c16617_1(url);
}} />)}
</View>
</BottomSheetScrollView>
</ActionSheet>;
};
export const ACTION_SHEET_KEY = "game-profile-store-links";
@@ -0,0 +1,42 @@
// Metro module 8643 (f8644).
import { useState, useCallback } from "react";
import { Pressable, View } from "react-native";
import { createStyles } from "../../../../design/components/Styles/native/createStyles";
import { GameProfileTrackActionActions } from "../../GameProfileAnalyticUtils";
import { intl, t } from "../../../../intl/index.native";
import { Text } from "../../../../design/components/Text/native/Text";
const useStyles = createStyles({
container: {
flexDirection: "column"
}
});
export default function GameProfileSummary(props) {
const { game, trackAction } = props;
const styles = useStyles();
const [state, setState] = useState(false);
const [state2, setState2] = useState(null);
const callback2 = useCallback((a0) => {
if (state2 == null) {
setState2(a0.nativeEvent.lines.length > 3);
}
}, [state2]);
const callback = useCallback(() => {
const r1 = !state;
trackAction(state ? GameProfileTrackActionActions.ShowLess : GameProfileTrackActionActions.ShowMore);
setState(r1);
}, [state, trackAction]);
let r17 = game?.summaryLocalized;
if (r17 == null) {
r17 = game?.description;
}
if (r17 == null) {
return null;
}
const accessibilityLabel = intl.string(state ? t["6MwJo/"] : t.lBeKY2);
return <View style={styles.container}>
<Text variant="text-md/normal" color="interactive-text-active" lineClamp={state ? void 0 : state2 == null ? void 0 : 3} onTextLayout={callback2}>{r17}</Text>
{state2 ? <Pressable onPress={callback} accessibilityRole="button" accessibilityLabel={accessibilityLabel}>
<Text variant="text-md/medium" color="text-brand">{accessibilityLabel}</Text>
</Pressable> : null}
</View>;
};
@@ -0,0 +1,84 @@
// Metro module 8515 (f8516).
import { useRef, useCallback } from "react";
import { View } from "react-native";
import { createStyles } from "../../../../design/components/Styles/native/createStyles";
import Module712 from "../../../../_bundle/Module712";
import useAnalyticsLocations, { AnalyticsLocationProvider } from "../../../app_analytics/useAnalyticsLocations";
import AnalyticsLocation from "../../../app_analytics/AnalyticsLocation";
import GameProfileHeader from "./GameProfileHeader";
import GameProfileMedia from "./GameProfileMedia";
import GameProfileStoreLinks from "./GameProfileStoreLinks";
import GameProfileReviews from "./GameProfileReviews";
import GameProfileSummary from "./GameProfileSummary";
import GameProfileLinkAccount from "./GameProfileLinkAccount";
import GameProfileCommunity from "./GameProfileCommunity";
import GameProfileAnnouncements from "./GameProfileAnnouncements";
import GameProfileShopCarousel from "./GameProfileShopCarousel";
import GameProfileSimilarGames from "./GameProfileSimilarGames";
import GameProfileDetails from "./GameProfileDetails";
import GameProfileGameClaimCta from "./GameProfileGameClaimCta";
import GameProfileReportButton from "./GameProfileReportButton";
const useStyles = createStyles({
container: {
flex: 1,
backgroundColor: Module712.colors.BACKGROUND_BASE_LOWEST,
paddingBottom: Module712.space.PX_16
},
body: {
flexDirection: "column",
paddingVertical: Module712.space.PX_16,
paddingHorizontal: Module712.space.PX_16,
gap: Module712.space.PX_32,
maxWidth: 520,
alignSelf: "center",
width: "100%"
},
buttonsContainer: {
flexDirection: "column",
gap: Module712.space.PX_8
}
});
export default function GameProfileView(props) {
const { game, invite, viewId, source, trackAction, onGuildInviteResolved, closeModal, scrollY, websiteButtons, onStoreLinksMeasured, onHeaderHeightMeasured, scrollOffsetRef } = props;
const styles = useStyles();
const ref = useRef(null);
const ref2 = useRef(null);
const analyticsLocations = useAnalyticsLocations(AnalyticsLocation.GAME_PROFILE).analyticsLocations;
const callback = useCallback(() => {
const current = ref.current;
const current2 = ref2.current;
if (current != null && current2 != null && onStoreLinksMeasured != null) {
onStoreLinksMeasured(current + current2);
}
}, [onStoreLinksMeasured]);
return <AnalyticsLocationProvider value={analyticsLocations}>
<View style={styles.container}>
<GameProfileHeader game={game} scrollY={scrollY} onHeightMeasured={onHeaderHeightMeasured} />
<View style={styles.body} onLayout={(event) => {
ref.current = event.nativeEvent.layout.y;
callback();
}}>
<GameProfileMedia game={game} viewId={viewId} source={source} trackAction={trackAction} />
{websiteButtons.length > 0 && <View onLayout={(event) => {
const layout = event.nativeEvent.layout;
ref2.current = layout.y + layout.height;
callback();
}}>
<GameProfileStoreLinks game={game} websiteButtons={websiteButtons} trackAction={trackAction} />
</View>}
<GameProfileReviews game={game} trackAction={trackAction} />
<GameProfileSummary game={game} viewId={viewId} source={source} trackAction={trackAction} />
<GameProfileLinkAccount game={game} analyticsLocations={analyticsLocations} trackAction={trackAction} />
<GameProfileCommunity closeModal={closeModal} game={game} onInviteResolved={onGuildInviteResolved} trackAction={trackAction} />
<GameProfileAnnouncements gameId={game.id} invite={invite} closeModal={closeModal} trackAction={trackAction} scrollOffsetRef={scrollOffsetRef} />
<GameProfileShopCarousel game={game} closeModal={closeModal} trackAction={trackAction} />
<GameProfileSimilarGames gameId={game.id} trackAction={trackAction} />
<GameProfileDetails game={game} viewId={viewId} source={source} trackAction={trackAction} />
<View style={styles.buttonsContainer}>
<GameProfileGameClaimCta game={game} trackAction={trackAction} />
<GameProfileReportButton applicationId={game.id} trackAction={trackAction} />
</View>
</View>
</View>
</AnalyticsLocationProvider>;
};
@@ -0,0 +1,12 @@
// Metro module 8530 (f8531).
import Module8531, { Circle } from "../../../../_bundle/Module8531";
export default function OpenCriticRatingCircle(props) {
const { rating, strokeColor, size } = props;
const cx = size / 2;
const r4 = (size - 4) / 2;
const strokeDasharray = 2 * Math.PI * r4;
const r44 = 1 - Math.min(Math.max(rating, 0), 100) / 100;
return <Module8531 width={size} height={size}>
<Circle transform={`rotate(${360 * r44 / 2} ${cx} ${cx})`} cx={cx} cy={cx} r={r4} stroke={strokeColor} strokeWidth={2} fill="none" strokeDasharray={strokeDasharray} strokeDashoffset={strokeDasharray * r44} />
</Module8531>;
};
@@ -0,0 +1,39 @@
// Metro module 8488 (f8489).
import { useEffect } from "react";
import GameProfileStore from "../../GameProfileStore";
import { isIOS } from "../../../../_bundle/Module501";
import { subscribeToIsInAppBrowserOpen } from "../../../links/native/BrowserManager";
import GameProfileActionCreators_native from "../../GameProfileActionCreators.native";
import { GameProfileSources } from "../../GameProfileAnalyticUtils";
export default function useInAppBrowserReturn({ gameId, scrollOffsetRef }) {
useEffect(() => {
if (gameId != null && isIOS()) {
let c26210_0 = false;
let c26210_1 = subscribeToIsInAppBrowserOpen((a0, a1) => {
if (!a1 && a0) {
c26210_0 = true;
GameProfileActionCreators_native.setGameProfilePendingReturn({
gameId,
initialScrollOffset: scrollOffsetRef.current
});
} else if (a1 && !a0) {
c26210_1();
c26210_0 = false;
const pendingReturn = GameProfileStore.getPendingReturn();
if (pendingReturn != null) {
GameProfileActionCreators_native.returnToGameProfile({
gameId: pendingReturn.gameId,
source: GameProfileSources.InAppBrowserReturn,
initialScrollOffset: pendingReturn.initialScrollOffset
});
}
}
});
return () => {
if (!c26210_0) {
c26210_1();
}
};
}
}, [gameId, scrollOffsetRef]);
};
@@ -0,0 +1,71 @@
// Metro module 8494 (f8495).
import { ThirdPartyGameApplicationWebsiteCategory } from "../../../../_bundle/Module8490";
import { SteamNeutralIcon } from "../../../../design/components/Icon/native/redesign/generated/SteamNeutralIcon";
import { GameProfileTrackActionActions } from "../../GameProfileAnalyticUtils";
import { intl, t } from "../../../../intl/index.native";
import { EpicGamesNeutralIcon } from "../../../../design/components/Icon/native/redesign/generated/EpicGamesNeutralIcon";
import { RobloxNeutralIcon } from "../../../../design/components/Icon/native/redesign/generated/RobloxNeutralIcon";
import { BattlenetNeutralIcon } from "../../../../design/components/Icon/native/redesign/generated/BattlenetNeutralIcon";
import { RiotGamesNeutralIcon } from "../../../../design/components/Icon/native/redesign/generated/RiotGamesNeutralIcon";
import { MinecraftNeutralIcon } from "../../../../design/components/Icon/native/redesign/generated/MinecraftNeutralIcon";
import { XboxNeutralIcon } from "../../../../design/components/Icon/native/redesign/generated/XboxNeutralIcon";
export default function getGameProfileStoreWebsiteData(a0) {
const category = a0.category;
if (ThirdPartyGameApplicationWebsiteCategory.STEAM === category) {
return {
icon: <SteamNeutralIcon size="md" />,
action: GameProfileTrackActionActions.SteamStoreLink,
title: intl.string(t.FsANs4),
url: a0.url
};
}
if (ThirdPartyGameApplicationWebsiteCategory.EPICGAMES === category) {
return {
icon: <EpicGamesNeutralIcon size="md" />,
action: GameProfileTrackActionActions.EpicStoreLink,
title: intl.string(t.ZbBMHa),
url: a0.url
};
}
if (ThirdPartyGameApplicationWebsiteCategory.ROBLOX === category) {
return {
icon: <RobloxNeutralIcon size="md" />,
action: GameProfileTrackActionActions.RobloxStoreLink,
title: intl.string(t["pJ+P+h"]),
url: a0.url
};
}
if (ThirdPartyGameApplicationWebsiteCategory.BATTLENET === category) {
return {
icon: <BattlenetNeutralIcon size="md" />,
action: GameProfileTrackActionActions.BattlenetStoreLink,
title: intl.string(t["A7grp+"]),
url: a0.url
};
}
if (ThirdPartyGameApplicationWebsiteCategory.RIOT === category) {
return {
icon: <RiotGamesNeutralIcon size="md" />,
action: GameProfileTrackActionActions.RiotStoreLink,
title: intl.string(t.h6MapL),
url: a0.url
};
}
if (ThirdPartyGameApplicationWebsiteCategory.MINECRAFT === category) {
return {
icon: <MinecraftNeutralIcon size="md" />,
action: GameProfileTrackActionActions.MinecraftStoreLink,
title: intl.string(t["HZbmO+"]),
url: a0.url
};
}
if (category === "XBOX_GAME_PASS") {
return {
icon: <XboxNeutralIcon size="md" />,
action: GameProfileTrackActionActions.XboxGamePassStoreLink,
title: intl.string(t["QpN/Iz"]),
url: a0.url
};
}
return null;
};
@@ -0,0 +1,80 @@
// Metro module 11934 (f11935).
import { ThirdPartyGameApplicationWebsiteCategory } from "../../../../_bundle/Module8490";
import { GlobeEarthIcon } from "../../../../design/components/Icon/native/redesign/generated/GlobeEarthIcon";
import { GameProfileTrackActionActions } from "../../GameProfileAnalyticUtils";
import { intl, t } from "../../../../intl/index.native";
import { XNeutralIcon } from "../../../../design/components/Icon/native/redesign/generated/XNeutralIcon";
import { YoutubeNeutralIcon } from "../../../../design/components/Icon/native/redesign/generated/YoutubeNeutralIcon";
import { FacebookNeutralIcon } from "../../../../design/components/Icon/native/redesign/generated/FacebookNeutralIcon";
import { InstagramNeutralIcon } from "../../../../design/components/Icon/native/redesign/generated/InstagramNeutralIcon";
import { BlueskyNeutralIcon } from "../../../../design/components/Icon/native/redesign/generated/BlueskyNeutralIcon";
import { RedditNeutralIcon } from "../../../../design/components/Icon/native/redesign/generated/RedditNeutralIcon";
import { TwitchNeutralIcon } from "../../../../design/components/Icon/native/redesign/generated/TwitchNeutralIcon";
export default function getGameProfileWebsiteData(a0, a1) {
const category = a0.category;
if (ThirdPartyGameApplicationWebsiteCategory.OFFICIAL === category) {
return {
icon: <GlobeEarthIcon size="md" color={a1} />,
action: GameProfileTrackActionActions.WebsiteLink,
title: intl.string(t.fOUKvg),
url: a0.url
};
}
if (ThirdPartyGameApplicationWebsiteCategory.TWITTER === category) {
return {
icon: <XNeutralIcon size="md" color={a1} />,
action: GameProfileTrackActionActions.XLink,
title: intl.string(t.INic4y),
url: a0.url
};
}
if (ThirdPartyGameApplicationWebsiteCategory.YOUTUBE === category) {
return {
icon: <YoutubeNeutralIcon size="md" color={a1} />,
action: GameProfileTrackActionActions.YouTubeLink,
title: intl.string(t.lNmxbE),
url: a0.url
};
}
if (ThirdPartyGameApplicationWebsiteCategory.FACEBOOK === category) {
return {
icon: <FacebookNeutralIcon size="md" color={a1} />,
action: GameProfileTrackActionActions.FacebookLink,
title: intl.string(t.FjyREK),
url: a0.url
};
}
if (ThirdPartyGameApplicationWebsiteCategory.INSTAGRAM === category) {
return {
icon: <InstagramNeutralIcon size="md" color={a1} />,
action: GameProfileTrackActionActions.InstagramLink,
title: intl.string(t["cgR+IK"]),
url: a0.url
};
}
if (ThirdPartyGameApplicationWebsiteCategory.BLUESKY === category) {
return {
icon: <BlueskyNeutralIcon size="md" color={a1} />,
action: GameProfileTrackActionActions.BlueskyLink,
title: intl.string(t["D/PHq5"]),
url: a0.url
};
}
if (ThirdPartyGameApplicationWebsiteCategory.REDDIT === category) {
return {
icon: <RedditNeutralIcon size="md" color={a1} />,
action: GameProfileTrackActionActions.RedditLink,
title: intl.string(t["Hgb+fc"]),
url: a0.url
};
}
if (ThirdPartyGameApplicationWebsiteCategory.TWITCH === category) {
return {
icon: <TwitchNeutralIcon size="md" color={a1} />,
action: GameProfileTrackActionActions.TwitchLink,
title: intl.string(t["7xtz4G"]),
url: a0.url
};
}
return null;
};
@@ -0,0 +1,71 @@
// Metro module 8658 (f8659).
import GuildStore from "../../stores/GuildStore";
import { GuildFeatures, JoinGuildSources, Routes } from "../../Constants";
import Module38 from "../../_bundle/Module38";
import { startLurking } from "../../utils/GuildDiscoveryUtils";
import InstantInviteActionCreators from "../../actions/InstantInviteActionCreators";
import { transitionTo } from "../routing/router_utils";
export default async function navigateToGameAnnouncement(c26257_0) {
let c26257_2;
let c29961_0, c29961_1, c29961_2, c29961_3, c29961_4, c29961_5, c29961_6, c29961_7;
L28: {
L27: {
c26257_2 = void 0;
c29961_0 = void 0;
c29961_1 = void 0;
c29961_2 = void 0;
c29961_3 = void 0;
c29961_4 = void 0;
c29961_0 = c26257_0.invite;
c29961_1 = c26257_0.guildId;
c29961_2 = c26257_0.channelId;
c29961_3 = c26257_0.messageId;
c29961_4 = c26257_0.analyticsLocationStack;
c29961_5 = void 0;
c29961_6 = void 0;
c29961_7 = void 0;
await void 0;
Module38(c29961_4.length > 0, "analyticsLocationStack must have at least one location");
c29961_5 = c29961_4[c29961_4.length - 1];
c29961_6 = null;
if (c29961_0 != null) {
c29961_1 = c29961_0.guild?.id;
c29961_6 = new Set(c29961_0.guild?.features);
}
if (c29961_1 == null) {
break L28;
}
c29961_7 = GuildStore.getGuild(c29961_1);
const joinedAt = c29961_7?.joinedAt;
L19: {
if (joinedAt == null) {
if (c29961_6 != null && !c29961_6.has(GuildFeatures.PREVIEW_ENABLED)) {
if (c29961_0 != null) {
await InstantInviteActionCreators.acceptInvite({
inviteKey: c29961_0.code,
context: {
location: c29961_5
},
skipOnboarding: true
});
break L19;
}
break L19;
}
await startLurking(c29961_1, {}, {
shouldNavigate: true,
channelId: c29961_2,
messageId: c29961_3,
joinSource: JoinGuildSources.GAME_PROFILE_ANNOUNCEMENTS
}, c29961_4);
break L27;
}
}
transitionTo(Routes.CHANNEL(c29961_1, c29961_2, c29961_3), {
sourceLocationStack: c29961_4
});
break L28;
}
return void 0;
}
};