[UI] Move to Discord's navigation stack
This commit is contained in:
parent
b175ac18c1
commit
a97293673d
6 changed files with 29 additions and 101 deletions
1
src/def.d.ts
vendored
1
src/def.d.ts
vendored
|
@ -289,7 +289,6 @@ interface VendettaObject {
|
||||||
interface VendettaPluginObject {
|
interface VendettaPluginObject {
|
||||||
manifest: PluginManifest,
|
manifest: PluginManifest,
|
||||||
storage: Indexable<any>,
|
storage: Indexable<any>,
|
||||||
showSettings: () => void,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
import { Indexable, PluginManifest, Plugin } from "@types";
|
import { Indexable, PluginManifest, Plugin } from "@types";
|
||||||
import { navigation } from "@metro/common";
|
|
||||||
import { awaitSyncWrapper, createStorage, wrapSync } from "@lib/storage";
|
import { awaitSyncWrapper, createStorage, wrapSync } from "@lib/storage";
|
||||||
import safeFetch from "@utils/safeFetch";
|
import safeFetch from "@utils/safeFetch";
|
||||||
import logger from "@lib/logger";
|
import logger from "@lib/logger";
|
||||||
import Subpage from "@ui/settings/components/Subpage";
|
|
||||||
|
|
||||||
// TODO: Properly implement hash-based updating
|
// TODO: Properly implement hash-based updating
|
||||||
|
|
||||||
|
@ -58,7 +56,6 @@ export async function evalPlugin(plugin: Plugin) {
|
||||||
manifest: plugin.manifest,
|
manifest: plugin.manifest,
|
||||||
// Wrapping this with wrapSync is NOT an option.
|
// Wrapping this with wrapSync is NOT an option.
|
||||||
storage: await createStorage<Indexable<any>>(plugin.id),
|
storage: await createStorage<Indexable<any>>(plugin.id),
|
||||||
showSettings: () => showSettings(plugin),
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const pluginString = `vendetta=>{return ${plugin.js}}\n//# sourceURL=${plugin.id}`;
|
const pluginString = `vendetta=>{return ${plugin.js}}\n//# sourceURL=${plugin.id}`;
|
||||||
|
@ -126,13 +123,3 @@ export async function initPlugins() {
|
||||||
const stopAllPlugins = () => Object.keys(plugins).forEach(p => stopPlugin(p, false));
|
const stopAllPlugins = () => Object.keys(plugins).forEach(p => stopPlugin(p, false));
|
||||||
|
|
||||||
export const getSettings = (id: string) => loadedPlugins[id]?.settings;
|
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,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
|
@ -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 { Forms, General } from "@ui/components";
|
||||||
import { Plugin } from "@types";
|
import { Plugin } from "@types";
|
||||||
import { getAssetIDByName } from "@ui/assets";
|
import { getAssetIDByName } from "@ui/assets";
|
||||||
import { showToast } from "@ui/toasts";
|
import { showToast } from "@ui/toasts";
|
||||||
import { removePlugin, startPlugin, stopPlugin, showSettings, getSettings } from "@lib/plugins";
|
import { removePlugin, startPlugin, stopPlugin, getSettings } from "@lib/plugins";
|
||||||
import copyText from "@lib/utils/copyText";
|
import copyText from "@utils/copyText";
|
||||||
|
|
||||||
const { FormRow, FormSwitch } = Forms;
|
const { FormRow, FormSwitch } = Forms;
|
||||||
const { TouchableOpacity, Image } = General;
|
const { TouchableOpacity, Image } = General;
|
||||||
|
@ -39,6 +39,8 @@ interface PluginCardProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function PluginCard({ plugin }: PluginCardProps) {
|
export default function PluginCard({ plugin }: PluginCardProps) {
|
||||||
|
const settings = getSettings(plugin.id);
|
||||||
|
const navigation = NavigationNative.useNavigation();
|
||||||
const [removed, setRemoved] = React.useState(false);
|
const [removed, setRemoved] = React.useState(false);
|
||||||
// This is needed because of React™
|
// This is needed because of React™
|
||||||
if (removed) return null;
|
if (removed) return null;
|
||||||
|
@ -86,7 +88,10 @@ export default function PluginCard({ plugin }: PluginCardProps) {
|
||||||
>
|
>
|
||||||
<Image style={styles.icon} source={getAssetIDByName(plugin.update ? "Check" : "Small")} />
|
<Image style={styles.icon} source={getAssetIDByName(plugin.update ? "Check" : "Small")} />
|
||||||
</TouchableOpacity>
|
</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")} />
|
<Image style={styles.icon} source={getAssetIDByName("settings")} />
|
||||||
</TouchableOpacity>}
|
</TouchableOpacity>}
|
||||||
</RN.View>
|
</RN.View>
|
||||||
|
|
|
@ -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>
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { i18n } from "@metro/common";
|
import { NavigationNative, i18n } from "@metro/common";
|
||||||
import { findByDisplayName } from "@metro/filters";
|
import { findByDisplayName } from "@metro/filters";
|
||||||
import { after } from "@lib/patcher";
|
import { after } from "@lib/patcher";
|
||||||
import findInReactTree from "@utils/findInReactTree";
|
import findInReactTree from "@utils/findInReactTree";
|
||||||
|
@ -6,6 +6,7 @@ import SettingsSection from "@ui/settings/components/SettingsSection";
|
||||||
import General from "@ui/settings/pages/General";
|
import General from "@ui/settings/pages/General";
|
||||||
import Plugins from "@ui/settings/pages/Plugins";
|
import Plugins from "@ui/settings/pages/Plugins";
|
||||||
import Developer from "@ui/settings/pages/Developer";
|
import Developer from "@ui/settings/pages/Developer";
|
||||||
|
import AssetBrowser from "@ui/settings/pages/AssetBrowser";
|
||||||
|
|
||||||
const screensModule = findByDisplayName("getScreens", false);
|
const screensModule = findByDisplayName("getScreens", false);
|
||||||
const settingsModule = findByDisplayName("UserSettingsOverviewWrapper", false);
|
const settingsModule = findByDisplayName("UserSettingsOverviewWrapper", false);
|
||||||
|
@ -22,11 +23,23 @@ export default function initSettings() {
|
||||||
},
|
},
|
||||||
VendettaPlugins: {
|
VendettaPlugins: {
|
||||||
title: "Plugins",
|
title: "Plugins",
|
||||||
render: Plugins
|
render: Plugins,
|
||||||
},
|
},
|
||||||
VendettaDeveloper: {
|
VendettaDeveloper: {
|
||||||
title: "Developer",
|
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 />;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
|
@ -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 { Forms } from "@ui/components";
|
||||||
import { getAssetIDByName } from "@ui/assets";
|
import { getAssetIDByName } from "@ui/assets";
|
||||||
import { showToast } from "@ui/toasts";
|
import { showToast } from "@ui/toasts";
|
||||||
|
@ -6,12 +6,11 @@ import { connectToDebugger } from "@lib/debug";
|
||||||
import { useProxy } from "@lib/storage";
|
import { useProxy } from "@lib/storage";
|
||||||
import settings from "@lib/settings";
|
import settings from "@lib/settings";
|
||||||
import logger from "@lib/logger";
|
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;
|
const { FormSection, FormRow, FormInput, FormDivider } = Forms;
|
||||||
|
|
||||||
export default function Developer() {
|
export default function Developer() {
|
||||||
|
const navigation = NavigationNative.useNavigation();
|
||||||
useProxy(settings);
|
useProxy(settings);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -52,10 +51,7 @@ export default function Developer() {
|
||||||
label="Asset Browser"
|
label="Asset Browser"
|
||||||
leading={<FormRow.Icon source={getAssetIDByName("ic_media_upload")} />}
|
leading={<FormRow.Icon source={getAssetIDByName("ic_media_upload")} />}
|
||||||
trailing={FormRow.Arrow}
|
trailing={FormRow.Arrow}
|
||||||
onPress={() => navigation.push(Subpage, {
|
onPress={() => navigation.push("VendettaAssetBrowser")}
|
||||||
name: "Asset Browser",
|
|
||||||
children: AssetBrowser,
|
|
||||||
})}
|
|
||||||
/>
|
/>
|
||||||
</FormSection>
|
</FormSection>
|
||||||
</RN.ScrollView>
|
</RN.ScrollView>
|
||||||
|
|
Loading…
Reference in a new issue