Update core plugin UI and add sort options to plugin list
- Refactor FixEmbed settings to use table-style rows and Stack layout - Add sort options to core plugins page for search and sorting - Protect certain core plugins from being toggled in PluginCard - Improve Search input to support explicit round style - Bump build version to dev1.1.1-1
This commit is contained in:
parent
6b7ec92149
commit
52116478d5
6 changed files with 145 additions and 91 deletions
|
|
@ -74,7 +74,7 @@ const config = {
|
|||
constModules: {
|
||||
globals: {
|
||||
"bunny-build-info": {
|
||||
version: `"1.1.0"`,
|
||||
version: `"dev1.1.1-1"`,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -5,13 +5,13 @@ import { logger } from "@lib/utils/logger";
|
|||
import { settings } from "@lib/api/settings";
|
||||
import { React } from "@metro/common";
|
||||
|
||||
const { FormSection, FormRow, FormSwitch, FormText } = findByProps(
|
||||
"FormSection",
|
||||
"FormRow",
|
||||
"FormSwitch",
|
||||
"FormText",
|
||||
const { TableRowGroup, TableRow, TableSwitchRow, Stack } = findByProps(
|
||||
"TableRowGroup",
|
||||
"TableRow",
|
||||
"TableSwitchRow",
|
||||
"Stack",
|
||||
);
|
||||
const { ScrollView } = require("react-native");
|
||||
const { ScrollView, Text } = require("react-native");
|
||||
|
||||
type FixEmbedSettings = {
|
||||
enabled: boolean;
|
||||
|
|
@ -101,60 +101,84 @@ export default defineCorePlugin({
|
|||
setConfig((prev) => ({ ...prev, [key]: value }));
|
||||
};
|
||||
|
||||
// Prefer table-style rows (TableRowGroup / TableSwitchRow) and Stack layout similar to other core plugins.
|
||||
const {
|
||||
TableRowGroup: _TRG,
|
||||
TableRow: _TR,
|
||||
TableSwitchRow: _TSR,
|
||||
Stack: _S,
|
||||
} = findByProps("TableRowGroup", "TableRow", "TableSwitchRow", "Stack");
|
||||
|
||||
// Fallback if the table-style components are not available in the host environment
|
||||
if (!_TRG || !_TSR || !_TR || !_S) {
|
||||
return React.createElement(
|
||||
ScrollView,
|
||||
{ style: { flex: 1, padding: 12 } },
|
||||
React.createElement(
|
||||
Text,
|
||||
null,
|
||||
"FixEmbed UI unavailable (missing TableRow components).",
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Use the resolved components
|
||||
const TableRowGroup = _TRG;
|
||||
const TableRow = _TR;
|
||||
const TableSwitchRow = _TSR;
|
||||
const Stack = _S;
|
||||
|
||||
return React.createElement(ScrollView, { style: { flex: 1 } }, [
|
||||
React.createElement(
|
||||
FormSection,
|
||||
{ title: "General Settings" },
|
||||
React.createElement(FormRow, {
|
||||
label: "Enable FixEmbed",
|
||||
subLabel: "Master switch for all link conversions",
|
||||
trailing: React.createElement(FormSwitch, {
|
||||
Stack,
|
||||
{ spacing: 8, style: { padding: 10 } },
|
||||
React.createElement(
|
||||
TableRowGroup,
|
||||
{ title: "General Settings" },
|
||||
React.createElement(TableSwitchRow, {
|
||||
label: "Enable FixEmbed",
|
||||
subLabel: "Master switch for all link conversions",
|
||||
value: config.enabled,
|
||||
onValueChange: (v: boolean) => updateConfig("enabled", v),
|
||||
}),
|
||||
}),
|
||||
),
|
||||
React.createElement(FormSection, { title: "Platforms" }, [
|
||||
React.createElement(FormRow, {
|
||||
label: "Twitter/X",
|
||||
trailing: React.createElement(FormSwitch, {
|
||||
value: config.twitter,
|
||||
disabled: !config.enabled,
|
||||
onValueChange: (v: boolean) => updateConfig("twitter", v),
|
||||
}),
|
||||
}),
|
||||
React.createElement(FormRow, {
|
||||
label: "Instagram",
|
||||
trailing: React.createElement(FormSwitch, {
|
||||
value: config.instagram,
|
||||
disabled: !config.enabled,
|
||||
onValueChange: (v: boolean) => updateConfig("instagram", v),
|
||||
}),
|
||||
}),
|
||||
React.createElement(FormRow, {
|
||||
label: "TikTok",
|
||||
trailing: React.createElement(FormSwitch, {
|
||||
value: config.tiktok,
|
||||
disabled: !config.enabled,
|
||||
onValueChange: (v: boolean) => updateConfig("tiktok", v),
|
||||
}),
|
||||
}),
|
||||
React.createElement(FormRow, {
|
||||
label: "Reddit",
|
||||
trailing: React.createElement(FormSwitch, {
|
||||
value: config.reddit,
|
||||
disabled: !config.enabled,
|
||||
onValueChange: (v: boolean) => updateConfig("reddit", v),
|
||||
}),
|
||||
}),
|
||||
]),
|
||||
React.createElement(
|
||||
FormSection,
|
||||
{ title: "About" },
|
||||
),
|
||||
React.createElement(
|
||||
FormText,
|
||||
{ style: { padding: 12 } },
|
||||
"This plugin automatically converts social media links to privacy-friendly alternative frontends for better embeds.",
|
||||
TableRowGroup,
|
||||
{ title: "Platforms" },
|
||||
React.createElement(TableSwitchRow, {
|
||||
label: "Twitter/X",
|
||||
value: config.twitter,
|
||||
onValueChange: (v: boolean) => updateConfig("twitter", v),
|
||||
disabled: !config.enabled,
|
||||
}),
|
||||
React.createElement(TableSwitchRow, {
|
||||
label: "Instagram",
|
||||
value: config.instagram,
|
||||
onValueChange: (v: boolean) => updateConfig("instagram", v),
|
||||
disabled: !config.enabled,
|
||||
}),
|
||||
React.createElement(TableSwitchRow, {
|
||||
label: "TikTok",
|
||||
value: config.tiktok,
|
||||
onValueChange: (v: boolean) => updateConfig("tiktok", v),
|
||||
disabled: !config.enabled,
|
||||
}),
|
||||
React.createElement(TableSwitchRow, {
|
||||
label: "Reddit",
|
||||
value: config.reddit,
|
||||
onValueChange: (v: boolean) => updateConfig("reddit", v),
|
||||
disabled: !config.enabled,
|
||||
}),
|
||||
),
|
||||
React.createElement(
|
||||
TableRowGroup,
|
||||
{ title: "About" },
|
||||
React.createElement(TableRow, {
|
||||
label: "Description",
|
||||
subLabel:
|
||||
"This plugin automatically converts social media links to privacy-friendly alternative frontends for better embeds.",
|
||||
disabled: true,
|
||||
}),
|
||||
),
|
||||
),
|
||||
]);
|
||||
|
|
|
|||
|
|
@ -29,6 +29,11 @@ export default function CorePlugins() {
|
|||
?.map((a: any) => (typeof a === "string" ? a : a.name))
|
||||
.join() || "",
|
||||
]}
|
||||
// Provide simple sort options so the Search input renders round and a sort menu appears
|
||||
sortOptions={{
|
||||
"Name (A-Z)": (a, b) => a.name.localeCompare(b.name),
|
||||
"Name (Z-A)": (a, b) => b.name.localeCompare(a.name),
|
||||
}}
|
||||
// Only core plugins: map corePluginInstances -> registeredPlugins -> unify
|
||||
items={[...corePluginInstances.keys()]
|
||||
.map((id) => registeredPlugins.get(id))
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { React, NavigationNative, tokens } from "@metro/common";
|
||||
import { CardWrapper } from "@core/ui/components/AddonCard";
|
||||
import { UnifiedPluginModel } from "@core/ui/settings/pages/Plugins/models";
|
||||
import { usePluginCardStyles } from "@core/ui/settings/pages/Plugins/usePluginCardStyles";
|
||||
import { findAssetId } from "@lib/api/assets";
|
||||
import { NavigationNative, tokens } from "@metro/common";
|
||||
import {
|
||||
Card,
|
||||
IconButton,
|
||||
|
|
@ -152,6 +152,11 @@ export default function PluginCard({
|
|||
[plugin, result],
|
||||
);
|
||||
|
||||
// Protect specific core plugins from being toggled
|
||||
const idLower = ((plugin.id || "") as string).toLowerCase();
|
||||
const isProtectedCore =
|
||||
idLower.includes("quickinstall") || idLower === "bunny.badges";
|
||||
|
||||
return (
|
||||
<CardContext.Provider value={cardContextValue}>
|
||||
<Card>
|
||||
|
|
@ -166,13 +171,18 @@ export default function PluginCard({
|
|||
<View>
|
||||
<Stack spacing={12} direction="horizontal">
|
||||
<Actions />
|
||||
<TableSwitch
|
||||
value={plugin.isEnabled()}
|
||||
onValueChange={(v: boolean) => {
|
||||
plugin.toggle(v);
|
||||
forceUpdate();
|
||||
}}
|
||||
/>
|
||||
{/* Dim and disable the switch for protected core plugins */}
|
||||
<View style={{ opacity: isProtectedCore ? 0.45 : 1 }}>
|
||||
<TableSwitch
|
||||
value={plugin.isEnabled()}
|
||||
disabled={isProtectedCore}
|
||||
onValueChange={(v: boolean) => {
|
||||
if (isProtectedCore) return;
|
||||
plugin.toggle(v);
|
||||
forceUpdate();
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
</Stack>
|
||||
</View>
|
||||
</View>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import { React } from "@metro/common";
|
||||
import { Strings } from "@core/i18n";
|
||||
import { findAssetId } from "@lib/api/assets";
|
||||
import { TextInput } from "@metro/common/components";
|
||||
|
|
@ -5,39 +6,53 @@ import ErrorBoundary from "@ui/components/ErrorBoundary";
|
|||
import { Image, View, ViewStyle } from "react-native";
|
||||
|
||||
export interface SearchProps {
|
||||
onChangeText?: (v: string) => void;
|
||||
placeholder?: string;
|
||||
style?: ViewStyle;
|
||||
isRound?: boolean;
|
||||
onChangeText?: (v: string) => void;
|
||||
placeholder?: string;
|
||||
style?: ViewStyle;
|
||||
isRound?: boolean;
|
||||
}
|
||||
|
||||
function SearchIcon() {
|
||||
return <Image style={{ width: 16, height: 16 }} source={findAssetId("icon-search")!} />;
|
||||
return (
|
||||
<Image
|
||||
style={{ width: 16, height: 16 }}
|
||||
source={findAssetId("icon-search")!}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default ({ onChangeText, placeholder, style, isRound }: SearchProps) => {
|
||||
const [query, setQuery] = React.useState("");
|
||||
const [query, setQuery] = React.useState("");
|
||||
|
||||
const onChange = (value: string) => {
|
||||
setQuery(value);
|
||||
onChangeText?.(value);
|
||||
};
|
||||
const onChange = (value: string) => {
|
||||
setQuery(value);
|
||||
onChangeText?.(value);
|
||||
};
|
||||
|
||||
return <ErrorBoundary>
|
||||
<View style={style}>
|
||||
<TextInput
|
||||
grow={true}
|
||||
isClearable={true}
|
||||
leadingIcon={SearchIcon}
|
||||
placeholder={placeholder ?? Strings.SEARCH}
|
||||
onChange={onChange}
|
||||
returnKeyType="search"
|
||||
size="md"
|
||||
autoCapitalize="none"
|
||||
autoCorrect={false}
|
||||
isRound={isRound}
|
||||
value={query}
|
||||
/>
|
||||
</View>
|
||||
</ErrorBoundary>;
|
||||
// When isRound is true, provide an explicit pill-style appearance so the
|
||||
// input looks rounded regardless of underlying component defaults.
|
||||
const inputStyle = isRound
|
||||
? ({ borderRadius: 9999, overflow: "hidden" } as ViewStyle)
|
||||
: undefined;
|
||||
|
||||
return (
|
||||
<ErrorBoundary>
|
||||
<View style={style}>
|
||||
<TextInput
|
||||
grow={true}
|
||||
isClearable={true}
|
||||
leadingIcon={SearchIcon}
|
||||
placeholder={placeholder ?? Strings.SEARCH}
|
||||
onChange={onChange}
|
||||
returnKeyType="search"
|
||||
size="md"
|
||||
autoCapitalize="none"
|
||||
autoCorrect={false}
|
||||
isRound={isRound}
|
||||
style={inputStyle}
|
||||
value={query}
|
||||
/>
|
||||
</View>
|
||||
</ErrorBoundary>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
2
src/modules.d.ts
vendored
2
src/modules.d.ts
vendored
|
|
@ -1,5 +1,5 @@
|
|||
declare module "bunny-build-info" {
|
||||
const version: "1.1.0";
|
||||
const version: "dev1.1.1-1";
|
||||
}
|
||||
|
||||
declare module "*.png" {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue