Enhance asset preview and remove changelog fetch

Bump bunny-build-info version to "1.1.6-1". Add robust asset previews:
normalize types, support more image formats and JSON/Lottie text
previews via requireModule, show scrollable formatted output and add
copy actions. Remove the changelog fetch/modal and related state from
General.
This commit is contained in:
kmmiio99o 2025-10-25 11:05:02 +02:00
parent 8f17366011
commit d4d491fa7a
3 changed files with 125 additions and 151 deletions

View file

@ -77,7 +77,7 @@ const config = {
constModules: {
globals: {
"bunny-build-info": {
version: `"1.1.6"`,
version: `"1.1.6-1"`,
},
},
},

View file

@ -4,62 +4,138 @@ import { findByProps } from "@metro";
import { clipboard } from "@metro/common";
import { Stack, TableRow, Text } from "@metro/common/components";
import { showToast } from "@ui/toasts";
import { Image } from "react-native";
import { Image, ScrollView } from "react-native";
import { requireModule } from "@metro/internals/modules";
const { openAlert } = lazyDestructure(() => findByProps("openAlert", "dismissAlert"));
const { AlertModal, AlertActionButton } = lazyDestructure(() => findByProps("AlertModal", "AlertActions"));
const { openAlert } = lazyDestructure(() =>
findByProps("openAlert", "dismissAlert"),
);
const { AlertModal, AlertActionButton } = lazyDestructure(() =>
findByProps("AlertModal", "AlertActions"),
);
const displayable = new Set(['png', 'jpg', 'svg']);
// More robust, normalized type checks and preview support.
// - Image types: standard raster/vector images
// - Text-like preview types: JSONA/JSON and Lottie (show raw JSON when possible)
const DISPLAYABLE_IMAGE_TYPES = new Set(["png", "jpg", "jpeg", "svg", "gif"]);
const DISPLAYABLE_TEXT_TYPES = new Set(["jsona", "json", "lottie"]);
const iconMap = {
jsona: 'ic_file_text',
lottie: 'ic_image',
webm: 'CirclePlayIcon-primary',
ttf: 'ic_add_text',
default: 'UnknownGameIcon'
// icon map uses lowercased keys
const iconMap: Record<string, string> = {
jsona: "ic_file_text",
lottie: "ic_image",
webm: "CirclePlayIcon-primary",
ttf: "ic_add_text",
default: "UnknownGameIcon",
};
interface AssetDisplayProps { asset: Asset; }
interface AssetDisplayProps {
asset: Asset;
}
export default function AssetDisplay({ asset }: AssetDisplayProps) {
// Normalize type checks to lowercase and guard against undefined
const type = String(asset.type ?? "").toLowerCase();
const isImage = DISPLAYABLE_IMAGE_TYPES.has(type);
const isTextPreview = DISPLAYABLE_TEXT_TYPES.has(type);
return (
<TableRow
variant={displayable.has(asset.type) ? 'default' : 'danger'}
label={asset.name}
subLabel={`Index: ${asset.id} Type: ${asset.type}`}
icon={
displayable.has(asset.type)
? <Image source={asset.id} style={{ width: 32, height: 32 }} />
: <TableRow.Icon
variant='danger'
source={findAssetId(asset.type in iconMap ? iconMap[asset.type as keyof typeof iconMap] : iconMap.default)}
/>
return (
<TableRow
variant={isImage || isTextPreview ? "default" : "danger"}
label={asset.name}
subLabel={`Index: ${asset.id} Type: ${asset.type}`}
icon={
isImage ? (
<Image source={asset.id} style={{ width: 32, height: 32 }} />
) : (
<TableRow.Icon
variant="danger"
source={findAssetId(
type in iconMap
? iconMap[type as keyof typeof iconMap]
: iconMap.default,
)}
/>
)
}
onPress={() =>
openAlert(
"revenge-asset-display-details",
<AlertModal
title={asset.name}
content={`Index: ${asset.id}\nModule ID: ${asset.moduleId}\nType: ${asset.type}`}
extraContent={
isImage ? (
<Image
resizeMode="contain"
source={asset.id}
style={{ flex: 1, width: "auto", height: 192 }}
/>
) : isTextPreview ? (
// For JSON-like assets (jsona, json, lottie) attempt to require the module
// and show a readable JSON/text preview. If loading fails, show a helpful message.
(() => {
try {
const moduleExport = requireModule(asset.moduleId);
const printable =
typeof moduleExport === "object"
? JSON.stringify(moduleExport, null, 2)
: String(moduleExport);
return (
<ScrollView style={{ maxHeight: 192, padding: 8 }}>
<Text
variant="text-sm/medium"
style={{ fontSize: 12, fontFamily: "monospace" }}
>
{printable}
</Text>
</ScrollView>
);
} catch (e) {
return (
<Text
variant="text-sm/medium"
color="text-warning"
style={{ width: "100%", textAlign: "center" }}
>
Could not load preview for {type.toUpperCase()}.
</Text>
);
}
})()
) : (
<Text
variant="text-sm/medium"
color="text-danger"
style={{ width: "100%", textAlign: "center" }}
>
Asset type {String(asset.type).toUpperCase()} is not supported
for preview.
</Text>
)
}
onPress={() =>
openAlert("revenge-asset-display-details", <AlertModal
title={asset.name}
content={`Index: ${asset.id}\nModule ID: ${asset.moduleId}\nType: ${asset.type}`}
extraContent={
displayable.has(asset.type)
? <Image resizeMode="contain" source={asset.id} style={{ flex: 1, width: 'auto', height: 192 }} />
: (<Text variant='text-sm/medium' color="text-danger" style={{ width: '100%', textAlign: 'center' }}>
Asset type {asset.type.toUpperCase()} is not supported for preview.
</Text>)
}
actions={
<Stack>
<AlertActionButton text="Copy asset name" variant="primary" onPress={() => copyToClipboard(asset.name)} />
<AlertActionButton text="Copy asset index" variant="secondary" onPress={() => copyToClipboard(asset.id.toString())} />
</Stack>
}
/>)
actions={
<Stack>
<AlertActionButton
text="Copy asset name"
variant="primary"
onPress={() => copyToClipboard(asset.name)}
/>
<AlertActionButton
text="Copy asset index"
variant="secondary"
onPress={() => copyToClipboard(asset.id.toString())}
/>
</Stack>
}
/>
);
/>,
)
}
/>
);
}
const copyToClipboard = (text: string) => {
clipboard.setString(text);
showToast.showCopyToClipboard();
};
clipboard.setString(text);
showToast.showCopyToClipboard();
};

View file

@ -18,13 +18,10 @@ import {
TableRow,
TableRowGroup,
TableSwitchRow,
Button,
Text,
} from "@metro/common/components";
import { Linking, ScrollView } from "react-native";
// Fetch latest commits from GitHub for Changelog
import React, { useState } from "react";
import React from "react";
export default function General() {
useProxy(settings);
@ -32,93 +29,6 @@ export default function General() {
const debugInfo = getDebugInfo();
const navigation = NavigationNative.useNavigation();
// Remove modal state, use openAlert for both modals
const [loadingCommits, setLoadingCommits] = useState(false);
const [commits, setCommits] = useState<any[]>([]);
const [commitsError, setCommitsError] = useState<string | null>(null);
// Handler for Changelog
const handleShowChangelog = () => {
setLoadingCommits(true);
setCommitsError(null);
fetch(
"https://api.github.com/repos/kmmiio99o/ShiggyCord/commits?per_page=10",
)
.then((res) => {
if (!res.ok) throw new Error("Failed to fetch commits");
return res.json();
})
.then((data) => {
setCommits(data);
setLoadingCommits(false);
openAlert(
"shiggycord-changelog",
<AlertModal
title="Changelog"
content={
loadingCommits ? (
<Text>Loading latest commits...</Text>
) : commitsError ? (
<Text style={{ color: "red" }}>{commitsError}</Text>
) : (
<Stack spacing={12}>
{data.map((entry: any) => (
<Stack key={entry.sha} spacing={2}>
<Text style={{ fontWeight: "bold" }}>
{new Date(
entry.commit.author.date,
).toLocaleDateString()}{" "}
— {entry.commit.author.name}
</Text>
<Text>{entry.commit.message.split("\n")[0]}</Text>
<Button
text="View Commit"
variant="secondary"
onPress={() => Linking.openURL(entry.html_url)}
style={{ alignSelf: "flex-start", marginTop: 2 }}
/>
</Stack>
))}
<Button
text="View All Commits on GitHub"
variant="primary"
onPress={() =>
Linking.openURL(
"https://github.com/kmmiio99o/ShiggyCord/commits/main/",
)
}
/>
</Stack>
)
}
actions={
<AlertActions>
<AlertActionButton text="Close" variant="secondary" />
</AlertActions>
}
/>,
);
})
.catch((e) => {
setCommitsError("Could not load changelog.");
setLoadingCommits(false);
openAlert(
"shiggycord-changelog-error",
<AlertModal
title="Changelog"
content={
<Text style={{ color: "red" }}>Could not load changelog.</Text>
}
actions={
<AlertActions>
<AlertActionButton text="Close" variant="secondary" />
</AlertActions>
}
/>,
);
});
};
// Team members array for easy editing
const TEAM_MEMBERS = [
{
@ -210,19 +120,7 @@ export default function General() {
}}
/>
</TableRowGroup>
<TableRowGroup title="Project Info">
<TableRow
arrow
label="Changelog"
subLabel="See what's new and recent changes"
icon={
<TableRow.Icon
source={findAssetId("CircleInformationIcon-primary")!}
/>
}
onPress={handleShowChangelog}
/>
</TableRowGroup>
<TableRowGroup title="Developer">
<TableSwitchRow
label={Strings.DEVELOPER_SETTINGS}