[UI] Overall overhaul

This commit is contained in:
Beef 2023-04-15 02:57:03 +01:00
parent 474aad2a47
commit 32b3a0295c
9 changed files with 81 additions and 78 deletions

View file

@ -0,0 +1,38 @@
import { Indexable } from "@types";
import { ReactNative as RN } from "@metro/common";
import { useProxy } from "@lib/storage";
import { HelpMessage, ErrorBoundary, Search } from "@ui/components";
import { CardWrapper } from "@ui/settings/components/Card";
import settings from "@lib/settings";
interface AddonPageProps<T> {
items: Indexable<T & { id: string }>;
safeModeMessage: string;
safeModeExtras?: JSX.Element | JSX.Element[];
card: React.ComponentType<CardWrapper<T>>;
}
export default function AddonPage<T>({ items, safeModeMessage, safeModeExtras, card: CardComponent }: AddonPageProps<T>) {
useProxy(settings)
useProxy(items);
const [search, setSearch] = React.useState("");
return (
<ErrorBoundary>
<RN.ScrollView style={{ flex: 1 }} contentContainerStyle={{ padding: 10 }}>
{settings.safeMode?.enabled && <RN.View style={{ marginBottom: 10 }}>
<HelpMessage messageType={0}>{safeModeMessage}</HelpMessage>
{safeModeExtras}
</RN.View>}
<Search
style={{ marginBottom: 10 }}
onChangeText={(v: string) => setSearch(v.toLowerCase())}
placeholder="Search"
/>
{/* TODO: When I am more awake, implement better searching than just by ID */}
{/* TODO: Also when I am more awake, make the search bar not scroll with the cards */}
{Object.values(items).filter(i => i.id?.toLowerCase().includes(search)).map((i, id) => <CardComponent item={i} index={id} />)}
</RN.ScrollView>
</ErrorBoundary>
)
}

View file

@ -1,5 +1,5 @@
import { Asset } from "@types";
import { ReactNative as RN, stylesheet, clipboard } from "@metro/common";
import { ReactNative as RN, clipboard } from "@metro/common";
import { showToast } from "@ui/toasts";
import { getAssetIDByName } from "@ui/assets";
import { Forms } from "@ui/components";
@ -10,18 +10,11 @@ interface AssetDisplayProps {
const { FormRow } = Forms;
const styles = stylesheet.createThemedStyleSheet({
asset: {
width: 32,
height: 32,
}
});
export default function AssetDisplay({ asset }: AssetDisplayProps) {
return (
<FormRow
label={`${asset.name} - ${asset.id}`}
trailing={<RN.Image source={asset.id} style={styles.asset} />}
trailing={<RN.Image source={asset.id} style={{ width: 32, height: 32 }} />}
onPress={() => {
clipboard.setString(asset.name);
showToast("Copied asset name to clipboard.", getAssetIDByName("toast_copy_link"));

View file

@ -13,8 +13,6 @@ const styles = stylesheet.createThemedStyleSheet({
card: {
backgroundColor: semanticColors?.BACKGROUND_SECONDARY,
borderRadius: 5,
marginHorizontal: 10,
marginBottom: 10,
},
header: {
padding: 0,
@ -44,6 +42,11 @@ interface OverflowAction extends Action {
isDestructive?: boolean;
}
export interface CardWrapper<T> {
item: T;
index: number;
}
interface CardProps {
index?: number;
headerLabel: string | React.ComponentType;
@ -61,7 +64,7 @@ export default function Card(props: CardProps) {
let pressableState = props.toggleValue ?? false;
return (
<RN.View style={[styles.card, { marginTop: props.index === 0 ? 10 : 0 }]}>
<RN.View style={[styles.card, { marginTop: props.index !== 0 ? 10 : 0 }]}>
<FormRow
style={styles.header}
label={props.headerLabel}

View file

@ -5,20 +5,15 @@ import { getAssetIDByName } from "@ui/assets";
import { showToast } from "@ui/toasts";
import { showConfirmationAlert } from "@ui/alerts";
import { removePlugin, startPlugin, stopPlugin, getSettings, fetchPlugin } from "@lib/plugins";
import Card from "@ui/settings/components/Card";
import Card, { CardWrapper } from "@ui/settings/components/Card";
interface PluginCardProps {
plugin: Plugin;
index: number;
}
async function stopThenStart(plugin: Plugin, func: Function) {
async function stopThenStart(plugin: Plugin, callback: Function) {
if (plugin.enabled) stopPlugin(plugin.id, false);
func();
callback();
if (plugin.enabled) await startPlugin(plugin.id);
}
export default function PluginCard({ plugin, index }: PluginCardProps) {
export default function PluginCard({ item: plugin, index }: CardWrapper<Plugin>) {
const settings = getSettings(plugin.id);
const navigation = NavigationNative.useNavigation();
const [removed, setRemoved] = React.useState(false);

View file

@ -12,7 +12,7 @@ export default function SettingsSection() {
return (
<ErrorBoundary>
<FormSection key="Vendetta" title="Vendetta">
<FormSection key="Vendetta" title={`Vendetta${settings.safeMode?.enabled ? " (Safe Mode)" : ""}`}>
<FormRow
label="General"
leading={<FormRow.Icon source={getAssetIDByName("settings")} />}

View file

@ -7,19 +7,14 @@ import { getAssetIDByName } from "@ui/assets";
import { showConfirmationAlert } from "@ui/alerts";
import { showToast } from "@ui/toasts";
import settings from "@lib/settings";
import Card from "@ui/settings/components/Card";
interface ThemeCardProps {
theme: Theme;
index: number;
}
import Card, { CardWrapper } from "@ui/settings/components/Card";
async function selectAndReload(value: boolean, id: string) {
await selectTheme(value ? id : "default");
BundleUpdaterManager.reload();
}
export default function ThemeCard({ theme, index }: ThemeCardProps) {
export default function ThemeCard({ item: theme, index }: CardWrapper<Theme>) {
useProxy(settings);
const [removed, setRemoved] = React.useState(false);

View file

@ -6,7 +6,6 @@ import AssetDisplay from "@ui/settings/components/AssetDisplay";
const { FormDivider } = Forms;
export default function AssetBrowser() {
const [search, setSearch] = React.useState("");
@ -14,17 +13,14 @@ export default function AssetBrowser() {
<ErrorBoundary>
<RN.View style={{ flex: 1 }}>
<Search
style={{ margin: 10 }}
onChangeText={(v: string) => setSearch(v)}
placeholder="Search"
/>
<RN.FlatList
data={Object.values(all).filter(a => a.name.includes(search) || a.id.toString() === search)}
renderItem={({ item }) => (
<>
<AssetDisplay asset={item} />
<FormDivider />
</>
)}
renderItem={({ item }) => <AssetDisplay asset={item} />}
ItemSeparatorComponent={FormDivider}
keyExtractor={item => item.name}
/>
</RN.View>

View file

@ -1,27 +1,18 @@
import { ReactNative as RN } from "@metro/common";
import { Plugin } from "@types";
import { useProxy } from "@lib/storage";
import { plugins } from "@lib/plugins";
import { HelpMessage } from "@ui/components";
import settings from "@lib/settings";
import AddonPage from "@ui/settings/components/AddonPage";
import PluginCard from "@ui/settings/components/PluginCard";
import ErrorBoundary from "@ui/components/ErrorBoundary";
export default function Plugins() {
useProxy(settings)
useProxy(plugins);
return (
<ErrorBoundary>
<RN.View style={{ flex: 1 }}>
{settings.safeMode?.enabled && <RN.View style={{ margin: 10 }}>
<HelpMessage messageType={0}>You are in Safe Mode, so plugins cannot be loaded. Disable any misbehaving plugins, then return to Normal Mode from the General settings page. </HelpMessage>
</RN.View>}
<RN.FlatList
data={Object.values(plugins)}
renderItem={({ item, index }) => <PluginCard plugin={item} index={index} />}
keyExtractor={item => item.id}
<AddonPage<Plugin>
items={plugins}
safeModeMessage="You are in Safe Mode, so plugins cannot be loaded. Disable any misbehaving plugins, then return to Normal Mode from the General settings page."
card={PluginCard}
/>
</RN.View>
</ErrorBoundary>
)
}

View file

@ -1,21 +1,19 @@
import { ButtonColors } from "@types";
import { ReactNative as RN } from "@metro/common";
import { themes } from "@lib/themes";
import { Theme, ButtonColors } from "@types";
import { useProxy } from "@lib/storage";
import { ErrorBoundary, Button, HelpMessage } from "@ui/components";
import { themes } from "@lib/themes";
import { Button } from "@ui/components";
import settings from "@lib/settings";
import AddonPage from "@ui/settings/components/AddonPage";
import ThemeCard from "@ui/settings/components/ThemeCard";
export default function Themes() {
useProxy(settings);
useProxy(themes);
return (
<ErrorBoundary>
<RN.View style={{ flex: 1 }}>
{settings.safeMode?.enabled && <RN.View style={{ margin: 10 }}>
<HelpMessage messageType={0}>You are in Safe Mode, meaning themes have been temporarily disabled.{settings.safeMode?.currentThemeId && " If a theme appears to be causing the issue, you can press below to disable it persistently."}</HelpMessage>
{settings.safeMode?.currentThemeId && <Button
<AddonPage<Theme>
items={themes}
safeModeMessage={`You are in Safe Mode, meaning themes have been temporarily disabled.${settings.safeMode?.currentThemeId ? " If a theme appears to be causing the issue, you can press below to disable it persistently." : ""}`}
safeModeExtras={settings.safeMode?.currentThemeId ? <Button
text="Disable Theme"
color={ButtonColors.BRAND}
size="small"
@ -23,14 +21,8 @@ export default function Themes() {
delete settings.safeMode?.currentThemeId;
}}
style={{ marginTop: 8 }}
/>}
</RN.View>}
<RN.FlatList
data={Object.values(themes)}
renderItem={({ item, index }) => <ThemeCard theme={item} index={index} />}
keyExtractor={item => item.id}
/> : undefined}
card={ThemeCard}
/>
</RN.View>
</ErrorBoundary>
)
}