[UI > Card] Move most actions into overflow action sheet (#43)
* [Plugin/ThemeCard] Move most actions into overflow action sheet * [UI > Card] Move overflow menu, add icon to header --------- Co-authored-by: Beef <beefers@riseup.net>
This commit is contained in:
parent
72c9055b5a
commit
ef702fb5ca
3 changed files with 79 additions and 44 deletions
|
@ -1,9 +1,12 @@
|
||||||
import { ReactNative as RN, stylesheet } from "@metro/common";
|
import { ReactNative as RN, stylesheet } from "@metro/common";
|
||||||
|
import { findByProps } from "@metro/filters";
|
||||||
import { Forms } from "@ui/components";
|
import { Forms } from "@ui/components";
|
||||||
import { getAssetIDByName } from "@ui/assets";
|
import { getAssetIDByName } from "@ui/assets";
|
||||||
import { semanticColors } from "@ui/color";
|
import { semanticColors } from "@ui/color";
|
||||||
|
|
||||||
const { FormRow, FormSwitch, FormRadio } = Forms;
|
const { FormRow, FormSwitch, FormRadio } = Forms;
|
||||||
|
const { hideActionSheet } = findByProps("openLazy", "hideActionSheet");
|
||||||
|
const { showSimpleActionSheet } = findByProps("showSimpleActionSheet");
|
||||||
|
|
||||||
// TODO: These styles work weirdly. iOS has cramped text, Android with low DPI probably does too. Fix?
|
// TODO: These styles work weirdly. iOS has cramped text, Android with low DPI probably does too. Fix?
|
||||||
const styles = stylesheet.createThemedStyleSheet({
|
const styles = stylesheet.createThemedStyleSheet({
|
||||||
|
@ -36,6 +39,11 @@ interface Action {
|
||||||
onPress: () => void;
|
onPress: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface OverflowAction extends Action {
|
||||||
|
label: string;
|
||||||
|
isDestructive?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
interface CardProps {
|
interface CardProps {
|
||||||
index?: number;
|
index?: number;
|
||||||
headerLabel: string | React.ComponentType;
|
headerLabel: string | React.ComponentType;
|
||||||
|
@ -45,13 +53,15 @@ interface CardProps {
|
||||||
onToggleChange?: (v: boolean) => void;
|
onToggleChange?: (v: boolean) => void;
|
||||||
descriptionLabel?: string | React.ComponentType;
|
descriptionLabel?: string | React.ComponentType;
|
||||||
actions?: Action[];
|
actions?: Action[];
|
||||||
|
overflowTitle?: string;
|
||||||
|
overflowActions?: OverflowAction[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Card(props: CardProps) {
|
export default function Card(props: CardProps) {
|
||||||
let pressableState = props.toggleValue ?? false;
|
let pressableState = props.toggleValue ?? false;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RN.View style={[styles.card, {marginTop: props.index === 0 ? 10 : 0}]}>
|
<RN.View style={[styles.card, { marginTop: props.index === 0 ? 10 : 0 }]}>
|
||||||
<FormRow
|
<FormRow
|
||||||
style={styles.header}
|
style={styles.header}
|
||||||
label={props.headerLabel}
|
label={props.headerLabel}
|
||||||
|
@ -76,6 +86,19 @@ export default function Card(props: CardProps) {
|
||||||
label={props.descriptionLabel}
|
label={props.descriptionLabel}
|
||||||
trailing={
|
trailing={
|
||||||
<RN.View style={styles.actions}>
|
<RN.View style={styles.actions}>
|
||||||
|
{props.overflowActions && <RN.TouchableOpacity
|
||||||
|
onPress={() => showSimpleActionSheet({
|
||||||
|
key: "CardOverflow",
|
||||||
|
header: {
|
||||||
|
title: props.overflowTitle,
|
||||||
|
icon: props.headerIcon && <FormRow.Icon style={{ marginRight: 8 }} source={getAssetIDByName(props.headerIcon)} />,
|
||||||
|
onClose: () => hideActionSheet(),
|
||||||
|
},
|
||||||
|
options: props.overflowActions?.map(i => ({ ...i, icon: getAssetIDByName(i.icon) })),
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<RN.Image style={styles.icon} source={getAssetIDByName("ic_more_24px")} />
|
||||||
|
</RN.TouchableOpacity>}
|
||||||
{props.actions?.map(({ icon, onPress }) => (
|
{props.actions?.map(({ icon, onPress }) => (
|
||||||
<RN.TouchableOpacity
|
<RN.TouchableOpacity
|
||||||
onPress={onPress}
|
onPress={onPress}
|
||||||
|
|
|
@ -20,7 +20,7 @@ export default function PluginCard({ plugin, index }: PluginCardProps) {
|
||||||
if (removed) return null;
|
if (removed) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card
|
<Card
|
||||||
index={index}
|
index={index}
|
||||||
// TODO: Actually make use of user IDs
|
// TODO: Actually make use of user IDs
|
||||||
headerLabel={`${plugin.manifest.name} by ${plugin.manifest.authors.map(i => i.name).join(", ")}`}
|
headerLabel={`${plugin.manifest.name} by ${plugin.manifest.authors.map(i => i.name).join(", ")}`}
|
||||||
|
@ -35,9 +35,28 @@ export default function PluginCard({ plugin, index }: PluginCardProps) {
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
descriptionLabel={plugin.manifest.description}
|
descriptionLabel={plugin.manifest.description}
|
||||||
actions={[
|
overflowTitle={plugin.manifest.name}
|
||||||
|
overflowActions={[
|
||||||
|
{
|
||||||
|
icon: "ic_download_24px",
|
||||||
|
label: plugin.update ? "Disable updates" : "Enable updates",
|
||||||
|
onPress: () => {
|
||||||
|
plugin.update = !plugin.update;
|
||||||
|
showToast(`${plugin.update ? "Enabled" : "Disabled"} updates for ${plugin.manifest.name}.`, getAssetIDByName("toast_image_saved"));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: "copy",
|
||||||
|
label: "Copy plugin URL",
|
||||||
|
onPress: () => {
|
||||||
|
clipboard.setString(plugin.id);
|
||||||
|
showToast("Copied plugin URL to clipboard.", getAssetIDByName("toast_copy_link"));
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
icon: "ic_message_delete",
|
icon: "ic_message_delete",
|
||||||
|
label: "Delete plugin",
|
||||||
|
isDestructive: true,
|
||||||
onPress: () => showConfirmationAlert({
|
onPress: () => showConfirmationAlert({
|
||||||
title: "Wait!",
|
title: "Wait!",
|
||||||
content: `Are you sure you wish to delete ${plugin.manifest.name}?`,
|
content: `Are you sure you wish to delete ${plugin.manifest.name}?`,
|
||||||
|
@ -54,20 +73,8 @@ export default function PluginCard({ plugin, index }: PluginCardProps) {
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
{
|
]}
|
||||||
icon: "copy",
|
actions={[
|
||||||
onPress: () => {
|
|
||||||
clipboard.setString(plugin.id);
|
|
||||||
showToast("Copied plugin URL to clipboard.", getAssetIDByName("toast_copy_link"));
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: plugin.update ? "Check" : "Small",
|
|
||||||
onPress: () => {
|
|
||||||
plugin.update = !plugin.update;
|
|
||||||
showToast(`${plugin.update ? "Enabled" : "Disabled"} updates for ${plugin.manifest.name}.`, getAssetIDByName("toast_image_saved"));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
...(settings ? [{
|
...(settings ? [{
|
||||||
icon: "settings",
|
icon: "settings",
|
||||||
onPress: () => navigation.push("VendettaCustomPage", {
|
onPress: () => navigation.push("VendettaCustomPage", {
|
||||||
|
|
|
@ -25,7 +25,7 @@ export default function ThemeCard({ theme, index }: ThemeCardProps) {
|
||||||
const authors = theme.data.authors;
|
const authors = theme.data.authors;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card
|
<Card
|
||||||
index={index}
|
index={index}
|
||||||
headerLabel={`${theme.data.name} ${authors ? `by ${authors.map(i => i.name).join(", ")}` : ""}`}
|
headerLabel={`${theme.data.name} ${authors ? `by ${authors.map(i => i.name).join(", ")}` : ""}`}
|
||||||
descriptionLabel={theme.data.description ?? "No description."}
|
descriptionLabel={theme.data.description ?? "No description."}
|
||||||
|
@ -34,34 +34,11 @@ export default function ThemeCard({ theme, index }: ThemeCardProps) {
|
||||||
onToggleChange={(v: boolean) => {
|
onToggleChange={(v: boolean) => {
|
||||||
selectAndReload(v, theme.id);
|
selectAndReload(v, theme.id);
|
||||||
}}
|
}}
|
||||||
actions={[
|
overflowTitle={theme.data.name}
|
||||||
{
|
overflowActions={[
|
||||||
icon: "ic_message_delete",
|
|
||||||
onPress: () => showConfirmationAlert({
|
|
||||||
title: "Wait!",
|
|
||||||
content: `Are you sure you wish to delete ${theme.data.name}?`,
|
|
||||||
confirmText: "Delete",
|
|
||||||
cancelText: "Cancel",
|
|
||||||
confirmColor: ButtonColors.RED,
|
|
||||||
onConfirm: () => {
|
|
||||||
removeTheme(theme.id).then((wasSelected) => {
|
|
||||||
setRemoved(true);
|
|
||||||
if (wasSelected) selectAndReload(false, theme.id);
|
|
||||||
}).catch((e: Error) => {
|
|
||||||
showToast(e.message, getAssetIDByName("Small"));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: "copy",
|
|
||||||
onPress: () => {
|
|
||||||
clipboard.setString(theme.id);
|
|
||||||
showToast("Copied theme URL to clipboard.", getAssetIDByName("toast_copy_link"));
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
icon: "ic_sync_24px",
|
icon: "ic_sync_24px",
|
||||||
|
label: "Refetch",
|
||||||
onPress: () => {
|
onPress: () => {
|
||||||
fetchTheme(theme.id).then(() => {
|
fetchTheme(theme.id).then(() => {
|
||||||
if (theme.selected) {
|
if (theme.selected) {
|
||||||
|
@ -81,6 +58,34 @@ export default function ThemeCard({ theme, index }: ThemeCardProps) {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
icon: "copy",
|
||||||
|
label: "Copy theme URL",
|
||||||
|
onPress: () => {
|
||||||
|
clipboard.setString(theme.id);
|
||||||
|
showToast("Copied theme URL to clipboard.", getAssetIDByName("toast_copy_link"));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: "ic_message_delete",
|
||||||
|
label: "Delete theme",
|
||||||
|
isDestructive: true,
|
||||||
|
onPress: () => showConfirmationAlert({
|
||||||
|
title: "Wait!",
|
||||||
|
content: `Are you sure you wish to delete ${theme.data.name}?`,
|
||||||
|
confirmText: "Delete",
|
||||||
|
cancelText: "Cancel",
|
||||||
|
confirmColor: ButtonColors.RED,
|
||||||
|
onConfirm: () => {
|
||||||
|
removeTheme(theme.id).then((wasSelected) => {
|
||||||
|
setRemoved(true);
|
||||||
|
if (wasSelected) selectAndReload(false, theme.id);
|
||||||
|
}).catch((e: Error) => {
|
||||||
|
showToast(e.message, getAssetIDByName("Small"));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in a new issue