ServerDrawer: add DM tile to the drawer grid, with a settings screen
This commit is contained in:
parent
68e478d7ca
commit
8bbfd6d7a5
5 changed files with 113 additions and 0 deletions
45
plugins/server-drawer/src/components/DmTile.tsx
Normal file
45
plugins/server-drawer/src/components/DmTile.tsx
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
import React from "react";
|
||||||
|
import { View, Pressable, Image, StyleSheet } from "react-native";
|
||||||
|
import { getAssetIDByName } from "@vendetta/ui/assets";
|
||||||
|
import { findByProps, findByName } from "@vendetta/metro";
|
||||||
|
|
||||||
|
const ICON = 48;
|
||||||
|
|
||||||
|
const ChatIcon = getAssetIDByName("ChatIcon");
|
||||||
|
const Haptic = findByProps("triggerHapticFeedback", "HapticFeedbackTypes");
|
||||||
|
const ChannelActions = findByProps("selectPrivateChannel");
|
||||||
|
const SelectedChannelStore = findByName("SelectedChannelStore");
|
||||||
|
const Flux = findByProps("useStateFromStores");
|
||||||
|
const NavContext = findByProps("getGuildId");
|
||||||
|
const colors = findByProps("colors", "unsafe_rawColors")?.colors;
|
||||||
|
|
||||||
|
function openDms() {
|
||||||
|
Haptic?.triggerHapticFeedback?.(Haptic.HapticFeedbackTypes.SOFT);
|
||||||
|
if (ChannelActions?.selectPrivateChannel) {
|
||||||
|
const lastChannelId = SelectedChannelStore?.getLastSelectedChannelId?.();
|
||||||
|
ChannelActions.selectPrivateChannel(lastChannelId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Was previously only reachable via the native left server rail's own DM shortcut icon - moved
|
||||||
|
// into the drawer's own grid instead, as the first tile, so DMs live in the same place as every
|
||||||
|
// other server rather than in a spot that only exists on the rail this plugin otherwise hides.
|
||||||
|
export default function DmTile() {
|
||||||
|
const selected = Flux?.useStateFromStores?.(
|
||||||
|
[NavContext],
|
||||||
|
() => NavContext?.getGuildId?.() == null,
|
||||||
|
) ?? false;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Pressable onPress={openDms} style={st.outer}>
|
||||||
|
<View style={[st.icon, { backgroundColor: selected ? (colors?.BG_ACCENT ?? "#5865f2") : "rgba(128,128,128,0.24)" }]}>
|
||||||
|
<Image source={ChatIcon} style={{ width: 24, height: 24, tintColor: "#fff" }} />
|
||||||
|
</View>
|
||||||
|
</Pressable>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const st = StyleSheet.create({
|
||||||
|
outer: { width: ICON, height: ICON },
|
||||||
|
icon: { width: ICON, height: ICON, borderRadius: 16, alignItems: "center", justifyContent: "center" },
|
||||||
|
});
|
||||||
|
|
@ -1,9 +1,12 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { View, Text, Pressable, Animated, Dimensions, StyleSheet, BackHandler } from "react-native";
|
import { View, Text, Pressable, Animated, Dimensions, StyleSheet, BackHandler } from "react-native";
|
||||||
import { find, findByProps, findByStoreName } from "@vendetta/metro";
|
import { find, findByProps, findByStoreName } from "@vendetta/metro";
|
||||||
|
import { storage } from "@vendetta/plugin";
|
||||||
|
import { useProxy } from "@vendetta/storage";
|
||||||
import { GuildNode } from "../utils/theme";
|
import { GuildNode } from "../utils/theme";
|
||||||
import GuildItem from "./GuildItem";
|
import GuildItem from "./GuildItem";
|
||||||
import FolderItem from "./FolderItem";
|
import FolderItem from "./FolderItem";
|
||||||
|
import DmTile from "./DmTile";
|
||||||
|
|
||||||
const Flux = findByProps("useStateFromStores");
|
const Flux = findByProps("useStateFromStores");
|
||||||
const SortedGuildStore = findByStoreName("SortedGuildStore");
|
const SortedGuildStore = findByStoreName("SortedGuildStore");
|
||||||
|
|
@ -54,6 +57,8 @@ function CreateJoinButton() {
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function ServerDrawerSheet({ gestureContext }: { gestureContext: any }) {
|
export default function ServerDrawerSheet({ gestureContext }: { gestureContext: any }) {
|
||||||
|
useProxy(storage);
|
||||||
|
|
||||||
const pick = React.useCallback((id: string) => {
|
const pick = React.useCallback((id: string) => {
|
||||||
Haptic?.triggerHapticFeedback(Haptic.HapticFeedbackTypes.SOFT);
|
Haptic?.triggerHapticFeedback(Haptic.HapticFeedbackTypes.SOFT);
|
||||||
if (Routing?.transitionToGuild) {
|
if (Routing?.transitionToGuild) {
|
||||||
|
|
@ -110,6 +115,7 @@ export default function ServerDrawerSheet({ gestureContext }: { gestureContext:
|
||||||
style={[st.grid, { paddingHorizontal: padX, gap: GAP }]}
|
style={[st.grid, { paddingHorizontal: padX, gap: GAP }]}
|
||||||
onLayout={onLayout}
|
onLayout={onLayout}
|
||||||
>
|
>
|
||||||
|
{!storage.hideDmTile && <DmTile />}
|
||||||
{nodes.map((node) =>
|
{nodes.map((node) =>
|
||||||
node.type === "folder"
|
node.type === "folder"
|
||||||
? <FolderItem key={node.id} node={node} onPick={pick} />
|
? <FolderItem key={node.id} node={node} onPick={pick} />
|
||||||
|
|
|
||||||
|
|
@ -5,12 +5,16 @@ import { patchGetQuestAsset } from "./patches/getQuestAsset";
|
||||||
import { patchExpanded, patchEmpty } from "./patches/contentPatch";
|
import { patchExpanded, patchEmpty } from "./patches/contentPatch";
|
||||||
import { patchHideGuildsBar } from "./patches/hideGuildsBar";
|
import { patchHideGuildsBar } from "./patches/hideGuildsBar";
|
||||||
import { patchCreateElement } from "./patches/createElementIntercept";
|
import { patchCreateElement } from "./patches/createElementIntercept";
|
||||||
|
import { storage } from "@vendetta/plugin";
|
||||||
|
import Settings from "./ui/Settings";
|
||||||
|
|
||||||
const TAG = "[ServerDrawer]";
|
const TAG = "[ServerDrawer]";
|
||||||
const cleanups: (() => void)[] = [];
|
const cleanups: (() => void)[] = [];
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
onLoad() {
|
onLoad() {
|
||||||
|
storage.hideDmTile ??= false;
|
||||||
|
|
||||||
console.log(TAG, "onLoad");
|
console.log(TAG, "onLoad");
|
||||||
|
|
||||||
let patched = 0;
|
let patched = 0;
|
||||||
|
|
@ -37,4 +41,5 @@ export default {
|
||||||
for (const fn of cleanups) fn();
|
for (const fn of cleanups) fn();
|
||||||
cleanups.length = 0;
|
cleanups.length = 0;
|
||||||
},
|
},
|
||||||
|
settings: Settings,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
29
plugins/server-drawer/src/ui/NoteBox.tsx
Normal file
29
plugins/server-drawer/src/ui/NoteBox.tsx
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
import { React, ReactNative } from "@vendetta/metro/common";
|
||||||
|
import { findByProps } from "@vendetta/metro";
|
||||||
|
|
||||||
|
const { View, Text } = ReactNative;
|
||||||
|
|
||||||
|
const colors = findByProps("colors", "unsafe_rawColors")?.colors;
|
||||||
|
|
||||||
|
/** Small bordered callout for explanatory text in a settings screen. */
|
||||||
|
export default function NoteBox({ children, style }: { children: any; style?: any }) {
|
||||||
|
const textColor = colors?.TEXT_MUTED ?? colors?.TEXT_NORMAL ?? "#96989d";
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View
|
||||||
|
style={[
|
||||||
|
{
|
||||||
|
marginHorizontal: 16,
|
||||||
|
marginVertical: 8,
|
||||||
|
padding: 10,
|
||||||
|
borderRadius: 8,
|
||||||
|
borderWidth: 1,
|
||||||
|
borderColor: "rgba(128,128,128,0.25)"
|
||||||
|
},
|
||||||
|
style
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<Text style={{ fontSize: 12.5, lineHeight: 18, opacity: 0.75, color: textColor }}>{children}</Text>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
28
plugins/server-drawer/src/ui/Settings.tsx
Normal file
28
plugins/server-drawer/src/ui/Settings.tsx
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
import { React } from "@vendetta/metro/common";
|
||||||
|
import { storage } from "@vendetta/plugin";
|
||||||
|
import { useProxy } from "@vendetta/storage";
|
||||||
|
import { TableRowGroup, TableSwitchRow } from "@shared/ui/table";
|
||||||
|
import SettingsScaffold from "@shared/ui/SettingsScaffold";
|
||||||
|
import NoteBox from "./NoteBox";
|
||||||
|
|
||||||
|
export default function Settings() {
|
||||||
|
useProxy(storage);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SettingsScaffold>
|
||||||
|
<NoteBox>
|
||||||
|
Server Drawer takes over the Quest Dock (the strip above the tab bar) to show your
|
||||||
|
servers as a grid instead - tap to expand, long-press a server for its usual context
|
||||||
|
menu, and the + button creates or joins a server through Discord's own modal.
|
||||||
|
</NoteBox>
|
||||||
|
<TableRowGroup title="Layout">
|
||||||
|
<TableSwitchRow
|
||||||
|
label="Hide the DMs tile"
|
||||||
|
subLabel="Remove the DMs tile from the drawer entirely"
|
||||||
|
value={!!storage.hideDmTile}
|
||||||
|
onValueChange={(v: boolean) => { storage.hideDmTile = v; }}
|
||||||
|
/>
|
||||||
|
</TableRowGroup>
|
||||||
|
</SettingsScaffold>
|
||||||
|
);
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue