[UI] Move to Discord's navigation stack

This commit is contained in:
Beef 2023-02-04 22:37:28 +00:00
parent b175ac18c1
commit a97293673d
6 changed files with 29 additions and 101 deletions

1
src/def.d.ts vendored
View file

@ -289,7 +289,6 @@ interface VendettaObject {
interface VendettaPluginObject {
manifest: PluginManifest,
storage: Indexable<any>,
showSettings: () => void,
}
declare global {

View file

@ -1,9 +1,7 @@
import { Indexable, PluginManifest, Plugin } from "@types";
import { navigation } from "@metro/common";
import { awaitSyncWrapper, createStorage, wrapSync } from "@lib/storage";
import safeFetch from "@utils/safeFetch";
import logger from "@lib/logger";
import Subpage from "@ui/settings/components/Subpage";
// TODO: Properly implement hash-based updating
@ -58,7 +56,6 @@ export async function evalPlugin(plugin: Plugin) {
manifest: plugin.manifest,
// Wrapping this with wrapSync is NOT an option.
storage: await createStorage<Indexable<any>>(plugin.id),
showSettings: () => showSettings(plugin),
}
};
const pluginString = `vendetta=>{return ${plugin.js}}\n//# sourceURL=${plugin.id}`;
@ -125,14 +122,4 @@ export async function initPlugins() {
const stopAllPlugins = () => Object.keys(plugins).forEach(p => stopPlugin(p, false));
export const getSettings = (id: string) => loadedPlugins[id]?.settings;
export function showSettings(plugin: Plugin) {
const settings = getSettings(plugin.id);
if (!settings) return logger.error(`Plugin ${plugin.id} is not loaded or has no settings`);
navigation.push(Subpage, {
name: plugin.manifest.name,
children: settings,
});
}
export const getSettings = (id: string) => loadedPlugins[id]?.settings;

View file

@ -1,10 +1,10 @@
import { ReactNative as RN, stylesheet } from "@metro/common";
import { ReactNative as RN, stylesheet, NavigationNative } from "@metro/common";
import { Forms, General } from "@ui/components";
import { Plugin } from "@types";
import { getAssetIDByName } from "@ui/assets";
import { showToast } from "@ui/toasts";
import { removePlugin, startPlugin, stopPlugin, showSettings, getSettings } from "@lib/plugins";
import copyText from "@lib/utils/copyText";
import { removePlugin, startPlugin, stopPlugin, getSettings } from "@lib/plugins";
import copyText from "@utils/copyText";
const { FormRow, FormSwitch } = Forms;
const { TouchableOpacity, Image } = General;
@ -39,6 +39,8 @@ interface PluginCardProps {
}
export default function PluginCard({ plugin }: PluginCardProps) {
const settings = getSettings(plugin.id);
const navigation = NavigationNative.useNavigation();
const [removed, setRemoved] = React.useState(false);
// This is needed because of React™
if (removed) return null;
@ -86,7 +88,10 @@ export default function PluginCard({ plugin }: PluginCardProps) {
>
<Image style={styles.icon} source={getAssetIDByName(plugin.update ? "Check" : "Small")} />
</TouchableOpacity>
{getSettings(plugin.id) && <TouchableOpacity onPress={() => showSettings(plugin)}>
{settings && <TouchableOpacity onPress={() => navigation.push("VendettaCustomPage", {
title: plugin.manifest.name,
render: settings,
})}>
<Image style={styles.icon} source={getAssetIDByName("settings")} />
</TouchableOpacity>}
</RN.View>

View file

@ -1,72 +0,0 @@
import { navigation, navigationStack, NavigationNative, stylesheet, constants } from "@metro/common";
import { General } from "@ui/components";
import { getAssetIDByName } from "@ui/assets";
interface SubpageProps {
name: string;
children: JSX.Element;
}
const styles = stylesheet.createThemedStyleSheet({
container: {
backgroundColor: stylesheet.ThemeColorMap.BACKGROUND_MOBILE_SECONDARY,
flex: 1,
},
card: {
backgroundColor: stylesheet.ThemeColorMap.BACKGROUND_MOBILE_PRIMARY,
color: stylesheet.ThemeColorMap.TEXT_NORMAL,
},
header: {
backgroundColor: stylesheet.ThemeColorMap.BACKGROUND_MOBILE_SECONDARY,
shadowColor: "transparent",
elevation: 0,
},
headerTitleContainer: {
color: stylesheet.ThemeColorMap.HEADER_PRIMARY,
},
headerTitle: {
fontFamily: constants.Fonts.PRIMARY_BOLD,
color: stylesheet.ThemeColorMap.HEADER_PRIMARY,
},
backIcon: {
tintColor: stylesheet.ThemeColorMap.INTERACTIVE_ACTIVE,
marginLeft: 15,
marginRight: 20,
}
});
export const Settings = navigationStack.createStackNavigator();
const { TouchableOpacity, Image } = General;
export default function Subpage({ name, children }: SubpageProps) {
return (
<NavigationNative.NavigationContainer independent>
<Settings.Navigator
initialRouteName={name}
style={styles.container}
screenOptions={{
cardOverlayEnabled: false,
cardShadowEnabled: false,
cardStyle: styles.card,
headerStyle: styles.header,
headerTitleContainerStyle: styles.headerTitleContainer,
}}
>
<Settings.Screen
name={name}
component={children}
options={{
headerTitleStyle: styles.headerTitle,
headerLeft: () => (
<TouchableOpacity
onPress={() => navigation.pop()}
>
<Image style={styles.backIcon} source={getAssetIDByName("back-icon")} />
</TouchableOpacity>
),
}}
/>
</Settings.Navigator>
</NavigationNative.NavigationContainer>
)
}

View file

@ -1,4 +1,4 @@
import { i18n } from "@metro/common";
import { NavigationNative, i18n } from "@metro/common";
import { findByDisplayName } from "@metro/filters";
import { after } from "@lib/patcher";
import findInReactTree from "@utils/findInReactTree";
@ -6,6 +6,7 @@ import SettingsSection from "@ui/settings/components/SettingsSection";
import General from "@ui/settings/pages/General";
import Plugins from "@ui/settings/pages/Plugins";
import Developer from "@ui/settings/pages/Developer";
import AssetBrowser from "@ui/settings/pages/AssetBrowser";
const screensModule = findByDisplayName("getScreens", false);
const settingsModule = findByDisplayName("UserSettingsOverviewWrapper", false);
@ -22,11 +23,23 @@ export default function initSettings() {
},
VendettaPlugins: {
title: "Plugins",
render: Plugins
render: Plugins,
},
VendettaDeveloper: {
title: "Developer",
render: Developer
render: Developer,
},
VendettaAssetBrowser: {
title: "Asset Browser",
render: AssetBrowser,
},
VendettaCustomPage: {
title: "Vendetta Page",
render: ({ render: PageView, ...options }: { render: React.ComponentType }) => {
const navigation = NavigationNative.useNavigation();
React.useEffect(() => options && navigation.setOptions(options));
return <PageView />;
}
}
}
}));

View file

@ -1,4 +1,4 @@
import { ReactNative as RN, navigation } from "@metro/common";
import { ReactNative as RN, NavigationNative } from "@metro/common";
import { Forms } from "@ui/components";
import { getAssetIDByName } from "@ui/assets";
import { showToast } from "@ui/toasts";
@ -6,12 +6,11 @@ import { connectToDebugger } from "@lib/debug";
import { useProxy } from "@lib/storage";
import settings from "@lib/settings";
import logger from "@lib/logger";
import Subpage from "@ui/settings/components/Subpage";
import AssetBrowser from "@ui/settings/pages/AssetBrowser";
const { FormSection, FormRow, FormInput, FormDivider } = Forms;
export default function Developer() {
const navigation = NavigationNative.useNavigation();
useProxy(settings);
return (
@ -52,10 +51,7 @@ export default function Developer() {
label="Asset Browser"
leading={<FormRow.Icon source={getAssetIDByName("ic_media_upload")} />}
trailing={FormRow.Arrow}
onPress={() => navigation.push(Subpage, {
name: "Asset Browser",
children: AssetBrowser,
})}
onPress={() => navigation.push("VendettaAssetBrowser")}
/>
</FormSection>
</RN.ScrollView>