diff --git a/src/plugins/crashHandler/index.ts b/src/plugins/crashHandler/index.ts index ab881e60c..221b115f6 100644 --- a/src/plugins/crashHandler/index.ts +++ b/src/plugins/crashHandler/index.ts @@ -175,7 +175,7 @@ export default definePlugin({ } if (settings.store.attemptToNavigateToHome) { try { - NavigationRouter.transitionTo("/channels/@me"); + NavigationRouter.transitionToGuild("@me"); } catch (err) { CrashHandlerLogger.debug("Failed to navigate to home", err); } diff --git a/src/plugins/keepCurrentChannel/index.ts b/src/plugins/keepCurrentChannel/index.ts index b226c34e3..1e0e742dc 100644 --- a/src/plugins/keepCurrentChannel/index.ts +++ b/src/plugins/keepCurrentChannel/index.ts @@ -19,7 +19,7 @@ import * as DataStore from "@api/DataStore"; import { Devs } from "@utils/constants"; import definePlugin from "@utils/types"; -import { ChannelStore, NavigationRouter, SelectedChannelStore, SelectedGuildStore } from "@webpack/common"; +import { ChannelRouter, SelectedChannelStore, SelectedGuildStore } from "@webpack/common"; export interface LogoutEvent { type: "LOGOUT"; @@ -40,11 +40,6 @@ interface PreviousChannel { let isSwitchingAccount = false; let previousCache: PreviousChannel | undefined; -function attemptToNavigateToChannel(guildId: string | null, channelId: string) { - if (!ChannelStore.hasChannel(channelId)) return; - NavigationRouter.transitionTo(`/channels/${guildId ?? "@me"}/${channelId}`); -} - export default definePlugin({ name: "KeepCurrentChannel", description: "Attempt to navigate to the channel you were in before switching accounts or loading Discord.", @@ -59,8 +54,9 @@ export default definePlugin({ if (!isSwitchingAccount) return; isSwitchingAccount = false; - if (previousCache?.channelId) - attemptToNavigateToChannel(previousCache.guildId, previousCache.channelId); + if (previousCache?.channelId) { + ChannelRouter.transitionToChannel(previousCache.channelId); + } }, async CHANNEL_SELECT({ guildId, channelId }: ChannelSelectEvent) { @@ -84,7 +80,7 @@ export default definePlugin({ await DataStore.set("KeepCurrentChannel_previousData", previousCache); } else if (previousCache.channelId) { - attemptToNavigateToChannel(previousCache.guildId, previousCache.channelId); + ChannelRouter.transitionToChannel(previousCache.channelId); } } }); diff --git a/src/plugins/userVoiceShow/components.tsx b/src/plugins/userVoiceShow/components.tsx index fad860dfa..f9a81c4b9 100644 --- a/src/plugins/userVoiceShow/components.tsx +++ b/src/plugins/userVoiceShow/components.tsx @@ -8,7 +8,7 @@ import { classNameFactory } from "@api/Styles"; import ErrorBoundary from "@components/ErrorBoundary"; import { classes } from "@utils/misc"; import { filters, findByCodeLazy, findByPropsLazy, findComponentByCodeLazy, findStoreLazy, mapMangledModuleLazy } from "@webpack"; -import { ChannelStore, GuildStore, IconUtils, match, NavigationRouter, P, PermissionsBits, PermissionStore, React, showToast, Text, Toasts, Tooltip, useMemo, UserStore, useStateFromStores } from "@webpack/common"; +import { ChannelRouter, ChannelStore, GuildStore, IconUtils, match, P, PermissionsBits, PermissionStore, React, showToast, Text, Toasts, Tooltip, useMemo, UserStore, useStateFromStores } from "@webpack/common"; import { Channel } from "discord-types/general"; const cl = classNameFactory("vc-uvs-"); @@ -24,6 +24,8 @@ const UserSummaryItem = findComponentByCodeLazy("defaultRenderUser", "showDefaul const Avatar = findComponentByCodeLazy(".AVATAR_STATUS_TYPING_16;"); const GroupDMAvatars = findComponentByCodeLazy(".AvatarSizeSpecs[", "getAvatarURL"); +const ActionButtonClasses = findByPropsLazy("actionButton", "highlight"); + interface IconProps extends React.ComponentPropsWithoutRef<"div"> { size?: number; } @@ -74,9 +76,10 @@ function LockedSpeakerIcon(props: IconProps) { interface VoiceChannelTooltipProps { channel: Channel; + isLocked: boolean; } -function VoiceChannelTooltip({ channel }: VoiceChannelTooltipProps) { +function VoiceChannelTooltip({ channel, isLocked }: VoiceChannelTooltipProps) { const voiceStates = useStateFromStores([VoiceStateStore], () => VoiceStateStore.getVoiceStatesForChannel(channel.id)); const users = useMemo( @@ -113,7 +116,7 @@ function VoiceChannelTooltip({ channel }: VoiceChannelTooltipProps) { {channelName}
- + {isLocked ? : } ; -export const VoiceChannelIndicator = ErrorBoundary.wrap(({ userId, size, isActionButton }: VoiceChannelIndicatorProps) => { +export const VoiceChannelIndicator = ErrorBoundary.wrap(({ userId, isMessageIndicator, isProfile, isActionButton, shouldHighlight }: VoiceChannelIndicatorProps) => { const channelId = useStateFromStores([VoiceStateStore], () => VoiceStateStore.getVoiceStateForUser(userId)?.channelId as string | undefined); const channel = channelId == null ? undefined : ChannelStore.getChannel(channelId); @@ -165,7 +170,7 @@ export const VoiceChannelIndicator = ErrorBoundary.wrap(({ userId, size, isActio selectVoiceChannel(channelId); } else { clickTimers[channelId] = setTimeout(() => { - NavigationRouter.transitionTo(`/channels/${channel.getGuildId() ?? "@me"}/${channelId}`); + ChannelRouter.transitionToChannel(channelId); delete clickTimers[channelId]; }, 250); } @@ -173,16 +178,16 @@ export const VoiceChannelIndicator = ErrorBoundary.wrap(({ userId, size, isActio return ( } + text={} tooltipClassName={cl("tooltip-container")} tooltipContentClassName={cl("tooltip-content")} > {props => { - const iconProps = { + const iconProps: IconProps = { ...props, - onClick, - size, - className: isActionButton ? cl("indicator-action-button") : cl("speaker-padding") + className: classes(isMessageIndicator && cl("message-indicator"), (!isProfile && !isActionButton) && cl("speaker-margin"), isActionButton && ActionButtonClasses.actionButton, shouldHighlight && ActionButtonClasses.highlight), + size: isActionButton ? 20 : undefined, + onClick }; return isLocked ? diff --git a/src/plugins/userVoiceShow/index.tsx b/src/plugins/userVoiceShow/index.tsx index 573fd0e38..98386a16e 100644 --- a/src/plugins/userVoiceShow/index.tsx +++ b/src/plugins/userVoiceShow/index.tsx @@ -19,6 +19,7 @@ import "./style.css"; import { addDecorator, removeDecorator } from "@api/MemberListDecorators"; +import { addDecoration, removeDecoration } from "@api/MessageDecorations"; import { definePluginSettings } from "@api/Settings"; import { Devs } from "@utils/constants"; import definePlugin, { OptionType } from "@utils/types"; @@ -37,13 +38,19 @@ const settings = definePluginSettings({ description: "Show a user's Voice Channel indicator in the member and DMs list", default: true, restartNeeded: true + }, + showInMessages: { + type: OptionType.BOOLEAN, + description: "Show a user's Voice Channel indicator in messages", + default: true, + restartNeeded: true } }); export default definePlugin({ name: "UserVoiceShow", description: "Shows an indicator when a user is in a Voice Channel", - authors: [Devs.LordElias, Devs.Nuckyz], + authors: [Devs.Nuckyz, Devs.LordElias], settings, patches: [ @@ -52,7 +59,7 @@ export default definePlugin({ find: ".Messages.USER_PROFILE_LOAD_ERROR", replacement: { match: /(\.fetchError.+?\?)null/, - replace: (_, rest) => `${rest}$self.VoiceChannelIndicator({userId:arguments[0]?.userId})` + replace: (_, rest) => `${rest}$self.VoiceChannelIndicator({userId:arguments[0]?.userId,isProfile:true})` }, predicate: () => settings.store.showInUserProfileModal }, @@ -79,8 +86,8 @@ export default definePlugin({ { find: "null!=this.peopleListItemRef.current", replacement: { - match: /\.actions,children:\[/, - replace: "$&$self.VoiceChannelIndicator({userId:this?.props?.user?.id,size:20,isActionButton:true})," + match: /\.actions,children:\[(?<=isFocused:(\i).+?)/, + replace: "$&$self.VoiceChannelIndicator({userId:this?.props?.user?.id,isActionButton:true,shouldHighlight:$1})," }, predicate: () => settings.store.showInMemberList } @@ -90,10 +97,14 @@ export default definePlugin({ if (settings.store.showInMemberList) { addDecorator("UserVoiceShow", ({ user }) => user == null ? null : ); } + if (settings.store.showInMessages) { + addDecoration("UserVoiceShow", ({ message }) => message?.author == null ? null : ); + } }, stop() { removeDecorator("UserVoiceShow"); + removeDecoration("UserVoiceShow"); }, VoiceChannelIndicator diff --git a/src/plugins/userVoiceShow/style.css b/src/plugins/userVoiceShow/style.css index 67f4c4958..d172975b8 100644 --- a/src/plugins/userVoiceShow/style.css +++ b/src/plugins/userVoiceShow/style.css @@ -13,16 +13,14 @@ color: var(--interactive-hover); } -.vc-uvs-speaker-padding { - padding: 0 4px; +.vc-uvs-speaker-margin { + margin-left: 4px; } -.vc-uvs-indicator-action-button { - background-color: var(--background-secondary); - border-radius: 100%; - height: 36px; - width: 36px; - margin-left: 10px; +.vc-uvs-message-indicator { + display: inline-flex; + top: 2.5px; + position: relative; } .vc-uvs-tooltip-container { diff --git a/src/webpack/common/types/utils.d.ts b/src/webpack/common/types/utils.d.ts index dd76d1ade..c0a930049 100644 --- a/src/webpack/common/types/utils.d.ts +++ b/src/webpack/common/types/utils.d.ts @@ -16,7 +16,7 @@ * along with this program. If not, see . */ -import { Guild, GuildMember, User } from "discord-types/general"; +import { Channel, Guild, GuildMember, User } from "discord-types/general"; import type { ReactNode } from "react"; import { LiteralUnion } from "type-fest"; @@ -173,6 +173,11 @@ export interface NavigationRouter { transitionToGuild(guildId: string, ...args: unknown[]): void; } +export interface ChannelRouter { + transitionToChannel: (channelId: string) => void; + transitionToThread: (channel: Channel) => void; +} + export interface IconUtils { getUserAvatarURL(user: User, canAnimate?: boolean, size?: number, format?: string): string; getDefaultAvatarURL(id: string, discriminator?: string): string; diff --git a/src/webpack/common/utils.ts b/src/webpack/common/utils.ts index b557f4da2..2d0026b58 100644 --- a/src/webpack/common/utils.ts +++ b/src/webpack/common/utils.ts @@ -149,6 +149,10 @@ export const NavigationRouter: t.NavigationRouter = mapMangledModuleLazy("Transi back: filters.byCode("goBack()"), forward: filters.byCode("goForward()"), }); +export const ChannelRouter: t.ChannelRouter = mapMangledModuleLazy('"Thread must have a parent ID."', { + transitionToChannel: filters.byCode(".preload"), + transitionToThread: filters.byCode('"Thread must have a parent ID."') +}); export let SettingsRouter: any; waitFor(["open", "saveAccountChanges"], m => SettingsRouter = m);