From dbf9e73a8be55f72822a277142f8d1d42e8504e9 Mon Sep 17 00:00:00 2001 From: everestmcarthur Date: Sat, 1 Aug 2026 18:47:38 +0000 Subject: [PATCH] deploy: 3ab3430c008b8dcacc297ff41421a2ba1cd1a348 --- plugins-data.json | 11 +++++++---- server-drawer/install/index.js | 2 +- server-drawer/install/manifest.json | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/plugins-data.json b/plugins-data.json index 4d10f61..d5e6f8b 100644 --- a/plugins-data.json +++ b/plugins-data.json @@ -137,20 +137,23 @@ "description": "Replaces the Quest Dock with a server grid drawer above the YouBar - tap to expand, long-press a server for its context menu, plus a one-tap create/join button.", "authors": [ "everestmcarthur", - "kmmiio99o" + "kmmiio99o", + "fres" ], "category": "Moderation & Appearance", "status": "revived", "accent": "#F97316", - "tagline": "Turns the Quest Dock into an expandable server grid, above the YouBar.", - "note": "Fork of kmmiio99o's ServerDrawer. One lookup (useMobileQuestDock) was missing an optional-chaining guard - if that lookup came back empty, the whole onLoad threw and every patch after it in the sequence never got applied, not just that one surface. Fixed, plus every patch call is now wrapped so a single bad lookup only skips its own surface.", + "tagline": "Turns the Quest Dock into an expandable server grid, with smarter folders.", + "note": "Fork of kmmiio99o's ServerDrawer. One lookup (useMobileQuestDock) was missing an optional-chaining guard - if that lookup came back empty, the whole onLoad threw and every patch after it in the sequence never got applied, not just that one surface. Fixed, plus every patch call is now wrapped so a single bad lookup only skips its own surface. Folder options (auto-collapse, hide preview icons) are adapted from fres621's BetterFolders - its icon-hiding half patched a \"GuildContainer\" component that no longer exists anywhere in current Discord builds (confirmed against decompiled source), and only applied to the native server rail anyway, which this plugin already replaces - so it's been rebuilt as a feature of the drawer's own folders instead.", "howItWorks": "Hijacks the Quest Dock - the strip Discord normally uses for daily quests, right above the tab bar - and puts a grid of your servers there instead. Tap it to expand, tap a server to jump to it, long-press for the usual context menu (mark as read, notification settings, leave, etc). A + button opens Discord's own create/join-server modal. Optionally hides the left server rail down to a single DMs icon, since your servers now live in the drawer instead.", "features": [ "Tap-to-expand server grid with folders, unread badges, and mention counts", "Long-press a server for its real context menu, not a rebuilt one", "One-tap create/join through Discord's native modal", "Optional: collapse the left server rail to a single DMs icon", - "Toggle unread badges independently" + "Toggle unread badges independently", + "Auto-collapse other open folders when you open a new one", + "Optional plain folder icon instead of the 4-server preview when collapsed" ], "commands": [], "limitations": "Depends on several internal Quest Dock lookups (11 in total) - each is individually guarded, so a future Discord rename degrades one surface at a time instead of breaking the whole plugin. Drawer position (left/right/top) is planned but not in this build yet - it currently only replaces the Quest Dock's native bottom position.", diff --git a/server-drawer/install/index.js b/server-drawer/install/index.js index 6a53d8d..33277f6 100644 --- a/server-drawer/install/index.js +++ b/server-drawer/install/index.js @@ -1 +1 @@ -(function(F,ue,y,i,a,n,o,le,G,ae,_e){"use strict";function ze(e){const t=i.findByProps("useIsMobileQuestDockRendered");if(!t?.useIsMobileQuestDockRendered)return!1;const r=t.useIsMobileQuestDockRendered;return t.useIsMobileQuestDockRendered=function(...s){return r.apply(this,s),!0},e.push(function(){t.useIsMobileQuestDockRendered=r}),!0}function Ue(e){const t=i.findByProps("useIsMobileQuestDockRenderedBase");if(!t?.useIsMobileQuestDockRenderedBase)return!1;const r=t.useIsMobileQuestDockRenderedBase;return t.useIsMobileQuestDockRenderedBase=function(...s){return r.apply(this,s),!0},e.push(function(){t.useIsMobileQuestDockRenderedBase=r}),!0}function ve(e){const t=i.findByProps("useMobileQuestDock");if(!t?.useMobileQuestDock)return!1;const r=t.useMobileQuestDock;return t.useMobileQuestDock=function(...s){return r.apply(this,s)||{id:"server-drawer",config:{quest_content_type:0,assets:{questBarHeroVideo:null,questBarHero:null},features:[]},userStatus:{enrolledAt:"2099-01-01",claimedAt:null},benefits:{rewards:[]},guildId:"0",tasks:[]}},e.push(function(){t.useMobileQuestDock=r}),!0}const qe="[ServerDrawer]";function Je(e){const t=i.findByProps("getQuestAsset");if(!t?.getQuestAsset)return console.log(qe,"WARN: getQuestAsset not found"),!1;const r=t.getQuestAsset;return t.getQuestAsset=function(...s){try{return r.apply(this,s)}catch{return{url:null,isAnimated:!1}}},e.push(function(){t.getQuestAsset=r}),!0}const Xe=i.findByStoreName("GuildStore"),Ke=i.findByProps("colors","unsafe_rawColors")?.colors;function ce({id:e,size:t=48}){const r=Xe?.getGuild(e);if(!r)return null;const s=t>=40?16:8;return r.icon?n.createElement(o.Image,{source:{uri:`https://cdn.discordapp.com/icons/${r.id}/${r.icon}.png?size=${t*2}`},style:{width:t,height:t,borderRadius:s}}):n.createElement(o.View,{style:[de.fallback,{width:t,height:t,borderRadius:s,backgroundColor:Ke?.BG_ACCENT??"#5865f2"}]},n.createElement(o.Text,{style:[de.letter,{fontSize:Math.max(10,t*.4)}]},r.name?.split(" ").map(function(u){return u[0]}).join("").slice(0,2).toUpperCase()||"?"))}const de=o.StyleSheet.create({fallback:{alignItems:"center",justifyContent:"center"},letter:{color:"#fff",fontWeight:"700"}}),Ye=i.findByStoreName("ThemeStore"),Ze=i.find(function(e){return e?.default?.internal?.resolveSemanticColor})?.default?.internal?.resolveSemanticColor??i.find(function(e){return e?.meta?.resolveSemanticColor})?.meta?.resolveSemanticColor??function(){};function $e(e,t=Ye?.theme){if(e)try{return Ze(t,e)}catch{return}}const fe=i.findByProps("TextStyleSheet")?.TextStyleSheet,pe=i.findByProps("triggerHapticFeedback","HapticFeedbackTypes");function Q(e,t){return $e(e)??t}const B=12,v=12,ge=42,q=220,he=4,I=16,M=20,ye={tension:200,friction:20};function Ne({visible:e,items:t,title:r,anchorX:s,anchorY:u,onClose:d}){const{width:f,height:k}=o.Dimensions.get("window"),w=(r?v+20+he:0)+t.length*ge;let m=s,g=u+48+10;m+q>f-B&&(m=f-q-B),mk-B&&(g=u-w-10),g0?n.createElement(o.View,{style:A.outline},n.createElement(o.View,{style:A.badge},n.createElement(o.Text,{style:A.text},t>99?"99+":String(t)))):r?n.createElement(o.View,{style:A.dotOutline},n.createElement(o.View,{style:A.dot})):null:null}function Ee({node:e,onPick:t}){const r=n.useRef(null),s=n.useRef(new o.Animated.Value(1)).current,u=function(){return o.Animated.spring(s,{toValue:.85,useNativeDriver:!0}).start()},d=function(){return o.Animated.spring(s,{toValue:1,useNativeDriver:!0}).start()},[f,k]=n.useState({visible:!1,items:[],title:"",x:0,y:0}),w=n.useCallback(function(){const R=e.id,l=et?.getGuild?.(R),b=i.find(function(h){return h?.default?.name==="getGuildsBarGuildMenuItems"})?.default??i.find(function(h){return typeof h?.default=="function"&&h.default.length<=2&&/guild/i.test(h.default.name??"")})?.default;if(!l||!b)return;const ne=tt?.getGuildsTree?.()?.version,D=b(R,ne);if(!D?.length)return;const P=r.current;P?.measure&&P.measure(function(h,oe,re,V,H,E){k({visible:!0,items:D.map(function(C){return{label:C.label??C.title??"Unknown",action:C.action,danger:C.variant==="destructive",iconSource:C.iconSource,IconComponent:C.IconComponent}}),title:l.name,x:H,y:E})})},[e.id]),m=n.useCallback(function(){be?.triggerHapticFeedback?.(be.HapticFeedbackTypes.IMPACT_MEDIUM),w()},[w]),g=e.id;return n.createElement(n.Fragment,null,n.createElement(o.Pressable,{onPressIn:u,onPressOut:d,onPress:function(){return t(g)},onLongPress:m,delayLongPress:500},n.createElement(o.View,{ref:r,style:Ce.outer,collapsable:!1},n.createElement(o.Animated.View,{style:[Ce.icon,{transform:[{scale:s}]}]},n.createElement(ce,{id:g})),n.createElement(nt,{guildId:g}))),n.createElement(Ne,{visible:f.visible,items:f.items,title:f.title,anchorX:f.x,anchorY:f.y,onClose:function(){return k(function(R){return{...R,visible:!1}})}}))}const Ce=o.StyleSheet.create({outer:{width:W,height:W},icon:{width:W,height:W,borderRadius:16,overflow:"hidden"}}),A=o.StyleSheet.create({outline:{position:"absolute",bottom:-3,right:-3,minWidth:23,minHeight:23,borderRadius:12,backgroundColor:"#1a1a2e",alignItems:"center",justifyContent:"center"},badge:{minWidth:19,height:19,borderRadius:9,backgroundColor:"#ed4245",alignItems:"center",justifyContent:"center",paddingHorizontal:5},text:{color:"#fff",fontSize:10,fontWeight:"700",lineHeight:19},dotOutline:{position:"absolute",bottom:-2,right:-2,width:14,height:14,borderRadius:7,backgroundColor:"#1a1a2e",alignItems:"center",justifyContent:"center"},dot:{width:10,height:10,borderRadius:5,backgroundColor:"#ed4245"}}),ot=i.findByProps("useStateFromStores");i.findByProps("colors","unsafe_rawColors")?.colors;const Se=i.findByStoreName("ExpandedGuildFolderStore");function rt(e){return ot?.useStateFromStores?.([Se],function(){const t=Se?.getExpandedFolders?.();return t instanceof Set?t.has(e):!1},[e])??!1}const it=i.findByProps("toggleGuildFolderExpand"),st=i.findByProps("useStateFromStores"),ke=i.findByStoreName("GuildReadStateStore"),x=48,X=16,ut=[{top:6,left:6},{top:6,right:6},{bottom:6,left:6},{bottom:6,right:6}],lt=ae.getAssetIDByName("FolderIcon");function we(e){return e==null?"#5865f2":`#${e.toString(16).padStart(6,"0")}`}function at({node:e}){const t=st?.useStateFromStores?.([ke],function(){let r=0;for(const s of e.children)r+=ke?.getMentionCount?.(s.id)??0;return r},[e.children])??0;return t>0?n.createElement(o.View,{style:Y.outline},n.createElement(o.View,{style:Y.badge},n.createElement(o.Text,{style:Y.text},t>99?"99+":String(t)))):null}function ct({node:e}){const t=we(e.color);return n.createElement(o.View,{style:K.outer},n.createElement(o.View,{style:[K.icon,{backgroundColor:t}]},e.children.slice(0,4).map(function(r,s){return n.createElement(o.View,{key:r.id,style:[K.cell,ut[s]]},n.createElement(ce,{id:r.id,size:X}))})),n.createElement(at,{node:e}))}const K=o.StyleSheet.create({outer:{width:x,height:x},icon:{width:x,height:x,borderRadius:16,overflow:"hidden"},cell:{position:"absolute",width:X,height:X,borderRadius:8,overflow:"hidden"}});function dt({children:e}){const t=n.useRef(new o.Animated.Value(0)).current;return n.useEffect(function(){o.Animated.timing(t,{toValue:1,duration:180,useNativeDriver:!0}).start()},[]),n.createElement(o.Animated.View,{style:{opacity:t}},e)}function ft({node:e,onPick:t}){const r=rt(e.id),s=function(){it?.toggleGuildFolderExpand?.(e.id)};return r?n.createElement(n.Fragment,null,n.createElement(o.Pressable,{onPress:s},n.createElement(o.View,{style:[Re.openIcon,{backgroundColor:we(e.color)}]},n.createElement(o.Image,{source:lt,style:Re.folderImg,tintColor:"#fff"}))),e.children.map(function(u){return n.createElement(dt,{key:u.id},n.createElement(Ee,{node:u,onPick:t}))})):n.createElement(o.Pressable,{onPress:s},n.createElement(ct,{node:e}))}const Re=o.StyleSheet.create({openIcon:{width:x,height:x,borderRadius:16,alignItems:"center",justifyContent:"center"},folderImg:{width:24,height:24}}),Y=o.StyleSheet.create({outline:{position:"absolute",bottom:-3,right:-3,minWidth:23,minHeight:23,borderRadius:12,backgroundColor:"#1a1a2e",alignItems:"center",justifyContent:"center"},badge:{minWidth:19,height:19,borderRadius:9,backgroundColor:"#ed4245",alignItems:"center",justifyContent:"center",paddingHorizontal:5},text:{color:"#fff",fontSize:10,fontWeight:"700",lineHeight:19}}),pt=i.findByProps("useStateFromStores"),Be=i.findByStoreName("SortedGuildStore"),gt=i.findByProps("getRootNavigationRef"),L=i.findByProps("triggerHapticFeedback","HapticFeedbackTypes"),De=i.findByProps("transitionToGuild"),ht=i.find(function(e){return typeof e?.handleCreateJoinGuildPress=="function"}),Pe=i.find(function(e){return e?.CirclePlusIcon})?.CirclePlusIcon,xe=i.findByProps("colors","unsafe_rawColors")?.unsafe_rawColors,yt=xe?.GREEN_360,Ie=xe?.WHITE,mt=i.find(function(e){return e?.QuestDockExternalCoordinationContext}),Ae=mt?.QuestDockExternalCoordinationContext,Te=i.find(function(e){return e?.QuestDockMode?.COLLAPSED!=null})?.QuestDockMode,j=48,_=6,bt=12;function Et(){const e=n.useRef(new o.Animated.Value(1)).current,t=n.useCallback(function(){o.Animated.spring(e,{toValue:.9,useNativeDriver:!0}).start()},[e]),r=n.useCallback(function(){o.Animated.spring(e,{toValue:1,useNativeDriver:!0}).start()},[e]),s=n.useCallback(function(){L?.triggerHapticFeedback?.(L.HapticFeedbackTypes.SOFT),ht?.handleCreateJoinGuildPress?.()},[]);return n.createElement(o.Pressable,{onPress:s,onPressIn:t,onPressOut:r},n.createElement(o.Animated.View,{style:[z.createJoin,{transform:[{scale:e}]}]},Pe?n.createElement(Pe,{size:"md",color:Ie}):n.createElement(o.Text,{style:z.createJoinFallback},"+")))}function Ve({gestureContext:e}){const t=n.useCallback(function(l){L?.triggerHapticFeedback(L.HapticFeedbackTypes.SOFT),De?.transitionToGuild?De.transitionToGuild(l,null):gt?.getRootNavigationRef()?.navigate("guilds",{guildId:l})},[]),r=pt?.useStateFromStores?.([Be],function(){return(Be?.getGuildsTree()?.root?.children||[]).filter(function(l){return l.type!=="root"})})??[],s=e?n.useContext(e):null,u=s?.minExpandedContentHeight,d=n.useCallback(function(l){if(!u)return;const b=l.nativeEvent.layout.height;u.get()!==b&&u.set(b)},[u]),f=(Ae?n.useContext(Ae):null)?.setRestingQuestDockMode,k=s?.questDockWrapperSpecs;n.useEffect(function(){if(!f||!Te||!k)return;const l=o.BackHandler.addEventListener("hardwareBackPress",function(){return(k.get()?.height??56)>80?(f(Te.COLLAPSED),!0):!1});return function(){return l.remove()}},[f,k]);const{width:w}=o.Dimensions.get("window"),m=Math.max(3,Math.floor((w-bt*2+_)/(j+_))),g=m*j+(m-1)*_,R=Math.max(0,(w-g)/2);return n.createElement(o.View,{style:z.alignTop},n.createElement(o.View,{style:[z.grid,{paddingHorizontal:R,gap:_}],onLayout:d},r.map(function(l){return l.type==="folder"?n.createElement(ft,{key:l.id,node:l,onPick:t}):n.createElement(Ee,{key:l.id,node:l,onPick:t})}),n.createElement(Et,null)))}const z=o.StyleSheet.create({alignTop:{flex:1,justifyContent:"flex-start",alignItems:"flex-start"},grid:{flexDirection:"row",flexWrap:"wrap",paddingTop:4,paddingBottom:16},createJoin:{width:j,height:j,borderRadius:16,backgroundColor:yt,alignItems:"center",justifyContent:"center"},createJoinFallback:{color:Ie,fontSize:28,fontWeight:"700",lineHeight:30}}),Z=new Map;let S=null,U=!1;function He(e,t,r){Z.set(e,{replacement:t,extraProps:r})}function Ct(e){if(U)return;if(S=a.React.createElement,!S){console.warn("[ServerDrawer] React.createElement is null, skipping patch");return}const t=function(r,s,...u){if(!S)return a.React.createElement(r,s,...u);const d=Z.get(r);if(d){const f=d.extraProps?{...s,...d.extraProps}:s;return S.call(a.React,d.replacement,f,...u)}return S.call(a.React,r,s,...u)};Object.assign(t,S),a.React.createElement=t,U=!0,e.push(function(){U&&S&&(a.React.createElement=S,U=!1),Z.clear()})}const $="[ServerDrawer]";let N=null;function Fe(){return N||(N=i.find(function(e){return e?.QuestDockGestureContext})?.QuestDockGestureContext??null),N}function St(e){const t=i.find(function(s){return s?.type?.displayName==="QuestDockContentExpanded"||s?.type?.name==="QuestDockContentExpanded"});if(!t?.type)return console.log($,"WARN: QuestDockContentExpanded not found (will retry)"),!1;const r=t.type;return He(r,Ve,{gestureContext:Fe()}),t.type=function(){return a.React.createElement(Ve,{gestureContext:Fe()})},e.push(function(){t.type=r}),console.log($,"PATCH: QuestDockContentExpanded replaced"),!0}function T(e,t){const r=i.find(function(d){return d?.type?.displayName===e||d?.type?.name===e});if(!r?.type)return console.log($,`WARN: ${e} not found`),!1;const s=r.type,u=s;return r.type=function(){return null},u&&(Object.defineProperties(r.type,Object.getOwnPropertyDescriptors(u)),r.type.displayName=e),t.push(function(){r.type=s}),!0}const kt="[ServerDrawer]",wt=ae.getAssetIDByName("ChatIcon"),Ge=i.findByProps("triggerHapticFeedback","HapticFeedbackTypes"),Qe=i.findByProps("selectPrivateChannel"),Rt=i.findByName("SelectedChannelStore"),Bt=i.findByProps("useStateFromStores"),Dt=Bt?.useStateFromStores,ee=i.findByProps("getGuildId"),te=i.findByProps("colors","unsafe_rawColors")?.colors,Pt=i.findByProps("ME"),xt=Pt?.ME??"/channels/@me";function It(){if(Ge?.triggerHapticFeedback(Ge.HapticFeedbackTypes.SOFT),Qe?.selectPrivateChannel){const e=Rt?.getLastSelectedChannelId?.();Qe.selectPrivateChannel(e)}}function At(){try{return ee?Dt([ee],function(){const e=ee?.getGuildId?.();return e==null||e===xt}):!1}catch{return!1}}function Me(){const e=At(),t=e?te?.WHITE??"#fff":te?.INTERACTIVE_NORMAL??"#80848e";return n.createElement(o.Pressable,{onPress:It,style:{flex:1,alignItems:"center",justifyContent:"center"}},e?n.createElement(o.View,{style:{position:"absolute",left:0,top:"25%",width:4,height:"50%",borderRadius:2,backgroundColor:te?.WHITE??"#fff"}}):null,n.createElement(o.Image,{source:wt,style:{width:28,height:28,tintColor:t}}))}function Tt(){const e=i.findByName("GuildsBar");if(e)return{default:e};let t=i.find(function(r){try{return r?.default?.type?.name==="GuildsBar"}catch{return!1}});return t?.default||(t=i.find(function(r){try{return r?.default?.displayName==="GuildsBar"}catch{return!1}}),t?.default)?t:null}function Vt(e){const t=Tt();if(!t?.default)return console.log(kt,"WARN: GuildsBar not found"),!1;const r=t.default;return He(r,Me),t.default=function(){return n.createElement(Me)},t.default.displayName="GuildsBar",e.push(function(){t.default=r}),!0}const{ScrollView:Ht,View:Ft}=a.ReactNative;function Gt({children:e}){return a.React.createElement(Ht,{style:{flex:1}},e,a.React.createElement(Ft,{style:{height:24}}))}const{View:Qt,Text:Mt}=a.ReactNative;function Wt({children:e,style:t}){return a.React.createElement(Qt,{style:[{marginHorizontal:16,marginVertical:8,padding:10,borderRadius:8,borderWidth:1,borderColor:"rgba(128,128,128,0.25)"},t]},a.React.createElement(Mt,{style:{fontSize:12.5,lineHeight:18,opacity:.75}},e))}const{FormSection:Ot,FormSwitchRow:We}=_e.Forms;function Lt(){return le.useProxy(y.storage),a.React.createElement(Gt,null,a.React.createElement(Wt,null,"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 use the + button to create or join a server through Discord's own modal."),a.React.createElement(Ot,{title:"Layout"},a.React.createElement(We,{label:"Hide the left server rail",subLabel:"Replaces it with a single DMs icon since your servers now live in the drawer",value:y.storage.hideGuildsBar!==!1,onValueChange:function(e){y.storage.hideGuildsBar=e,je()}}),a.React.createElement(We,{label:"Unread badges",subLabel:"Show mention counts and unread dots on server icons in the drawer",value:y.storage.showUnreadBadges!==!1,onValueChange:function(e){y.storage.showUnreadBadges=e}})))}let c=[];function p(e,t){try{return t()}catch(r){return ue.logger.error(`[ServerDrawer] "${e}" patch threw, skipping: ${r}`),!1}}function Oe(){const e=[];Ct(c),p("questDockRender",function(){return ze(c)})&&e.push("questDockRender"),p("questDockBase",function(){return Ue(c)})&&e.push("questDockBase"),p("mobileQuestDock",function(){return ve(c)})&&e.push("mobileQuestDock"),p("getQuestAsset",function(){return Je(c)})&&e.push("getQuestAsset"),p("expanded",function(){return St(c)})&&e.push("expanded"),p("collapsed",function(){return T("QuestDockContentCollapsed",c)})&&e.push("collapsed"),p("enrolledHeader",function(){return T("QuestDockEnrolledHeader",c)})&&e.push("enrolledHeader"),p("unenrolledHeader",function(){return T("QuestDockUnenrolledHeader",c)})&&e.push("unenrolledHeader"),p("enrolledBody",function(){return T("QuestDockEnrolledBody",c)})&&e.push("enrolledBody"),p("unenrolledBody",function(){return T("QuestDockUnenrolledBody",c)})&&e.push("unenrolledBody"),y.storage.hideGuildsBar&&p("hideGuildsBar",function(){return Vt(c)})&&e.push("hideGuildsBar"),ue.logger.log(`[ServerDrawer] onLoad done - ${e.length}/11 patches applied (${e.join(", ")||"none"})`)}function Le(){for(const e of c)try{e()}catch{}c=[]}function je(){Le(),Oe()}var jt={onLoad:function(){y.storage.hideGuildsBar??=!0,y.storage.showUnreadBadges??=!0,Oe()},onUnload:function(){return Le()},settings:Lt};return F.default=jt,F.restart=je,Object.defineProperty(F,"__esModule",{value:!0}),F})({},vendetta,vendetta.plugin,vendetta.metro,vendetta.metro.common,window.React,vendetta.metro.common.ReactNative,vendetta.storage,vendetta.ui,vendetta.ui.assets,vendetta.ui.components); +(function(V,de,d,s,u,n,o,X,H,ce,ze){"use strict";function qe(e){const t=s.findByProps("useIsMobileQuestDockRendered");if(!t?.useIsMobileQuestDockRendered)return!1;const r=t.useIsMobileQuestDockRendered;return t.useIsMobileQuestDockRendered=function(...i){return r.apply(this,i),!0},e.push(function(){t.useIsMobileQuestDockRendered=r}),!0}function Xe(e){const t=s.findByProps("useIsMobileQuestDockRenderedBase");if(!t?.useIsMobileQuestDockRenderedBase)return!1;const r=t.useIsMobileQuestDockRenderedBase;return t.useIsMobileQuestDockRenderedBase=function(...i){return r.apply(this,i),!0},e.push(function(){t.useIsMobileQuestDockRenderedBase=r}),!0}function Je(e){const t=s.findByProps("useMobileQuestDock");if(!t?.useMobileQuestDock)return!1;const r=t.useMobileQuestDock;return t.useMobileQuestDock=function(...i){return r.apply(this,i)||{id:"server-drawer",config:{quest_content_type:0,assets:{questBarHeroVideo:null,questBarHero:null},features:[]},userStatus:{enrolledAt:"2099-01-01",claimedAt:null},benefits:{rewards:[]},guildId:"0",tasks:[]}},e.push(function(){t.useMobileQuestDock=r}),!0}const Ke="[ServerDrawer]";function Ye(e){const t=s.findByProps("getQuestAsset");if(!t?.getQuestAsset)return console.log(Ke,"WARN: getQuestAsset not found"),!1;const r=t.getQuestAsset;return t.getQuestAsset=function(...i){try{return r.apply(this,i)}catch{return{url:null,isAnimated:!1}}},e.push(function(){t.getQuestAsset=r}),!0}const Ze=s.findByStoreName("GuildStore"),$e=s.findByProps("colors","unsafe_rawColors")?.colors;function fe({id:e,size:t=48}){const r=Ze?.getGuild(e);if(!r)return null;const i=t>=40?16:8;return r.icon?n.createElement(o.Image,{source:{uri:`https://cdn.discordapp.com/icons/${r.id}/${r.icon}.png?size=${t*2}`},style:{width:t,height:t,borderRadius:i}}):n.createElement(o.View,{style:[he.fallback,{width:t,height:t,borderRadius:i,backgroundColor:$e?.BG_ACCENT??"#5865f2"}]},n.createElement(o.Text,{style:[he.letter,{fontSize:Math.max(10,t*.4)}]},r.name?.split(" ").map(function(l){return l[0]}).join("").slice(0,2).toUpperCase()||"?"))}const he=o.StyleSheet.create({fallback:{alignItems:"center",justifyContent:"center"},letter:{color:"#fff",fontWeight:"700"}}),Ne=s.findByStoreName("ThemeStore"),et=s.find(function(e){return e?.default?.internal?.resolveSemanticColor})?.default?.internal?.resolveSemanticColor??s.find(function(e){return e?.meta?.resolveSemanticColor})?.meta?.resolveSemanticColor??function(){};function tt(e,t=Ne?.theme){if(e)try{return et(t,e)}catch{return}}const pe=s.findByProps("TextStyleSheet")?.TextStyleSheet,ge=s.findByProps("triggerHapticFeedback","HapticFeedbackTypes");function Q(e,t){return tt(e)??t}const D=12,J=12,ye=42,K=220,me=4,F=16,M=20,be={tension:200,friction:20};function nt({visible:e,items:t,title:r,anchorX:i,anchorY:l,onClose:c}){const{width:h,height:k}=o.Dimensions.get("window"),R=(r?J+20+me:0)+t.length*ye;let m=i,g=l+48+10;m+K>h-D&&(m=h-K-D),mk-D&&(g=l-R-10),g0?n.createElement(o.View,{style:x.outline},n.createElement(o.View,{style:x.badge},n.createElement(o.Text,{style:x.text},t>99?"99+":String(t)))):r?n.createElement(o.View,{style:x.dotOutline},n.createElement(o.View,{style:x.dot})):null:null}function Se({node:e,onPick:t}){const r=n.useRef(null),i=n.useRef(new o.Animated.Value(1)).current,l=function(){return o.Animated.spring(i,{toValue:.85,useNativeDriver:!0}).start()},c=function(){return o.Animated.spring(i,{toValue:1,useNativeDriver:!0}).start()},[h,k]=n.useState({visible:!1,items:[],title:"",x:0,y:0}),R=n.useCallback(function(){const B=e.id,a=ot?.getGuild?.(B),b=s.find(function(y){return y?.default?.name==="getGuildsBarGuildMenuItems"})?.default??s.find(function(y){return typeof y?.default=="function"&&y.default.length<=2&&/guild/i.test(y.default.name??"")})?.default;if(!a||!b)return;const se=rt?.getGuildsTree?.()?.version,I=b(B,se);if(!I?.length)return;const P=r.current;P?.measure&&P.measure(function(y,ie,le,G,T,E){k({visible:!0,items:I.map(function(C){return{label:C.label??C.title??"Unknown",action:C.action,danger:C.variant==="destructive",iconSource:C.iconSource,IconComponent:C.IconComponent}}),title:a.name,x:T,y:E})})},[e.id]),m=n.useCallback(function(){Ce?.triggerHapticFeedback?.(Ce.HapticFeedbackTypes.IMPACT_MEDIUM),R()},[R]),g=e.id;return n.createElement(n.Fragment,null,n.createElement(o.Pressable,{onPressIn:l,onPressOut:c,onPress:function(){return t(g)},onLongPress:m,delayLongPress:500},n.createElement(o.View,{ref:r,style:we.outer,collapsable:!1},n.createElement(o.Animated.View,{style:[we.icon,{transform:[{scale:i}]}]},n.createElement(fe,{id:g})),n.createElement(st,{guildId:g}))),n.createElement(nt,{visible:h.visible,items:h.items,title:h.title,anchorX:h.x,anchorY:h.y,onClose:function(){return k(function(B){return{...B,visible:!1}})}}))}const we=o.StyleSheet.create({outer:{width:L,height:L},icon:{width:L,height:L,borderRadius:16,overflow:"hidden"}}),x=o.StyleSheet.create({outline:{position:"absolute",bottom:-3,right:-3,minWidth:23,minHeight:23,borderRadius:12,backgroundColor:"#1a1a2e",alignItems:"center",justifyContent:"center"},badge:{minWidth:19,height:19,borderRadius:9,backgroundColor:"#ed4245",alignItems:"center",justifyContent:"center",paddingHorizontal:5},text:{color:"#fff",fontSize:10,fontWeight:"700",lineHeight:19},dotOutline:{position:"absolute",bottom:-2,right:-2,width:14,height:14,borderRadius:7,backgroundColor:"#1a1a2e",alignItems:"center",justifyContent:"center"},dot:{width:10,height:10,borderRadius:5,backgroundColor:"#ed4245"}}),it=s.findByProps("useStateFromStores");s.findByProps("colors","unsafe_rawColors")?.colors;const ke=s.findByStoreName("ExpandedGuildFolderStore");function lt(e){return it?.useStateFromStores?.([ke],function(){const t=ke?.getExpandedFolders?.();return t instanceof Set?t.has(e):!1},[e])??!1}const ut=s.findByProps("toggleGuildFolderExpand"),at=s.findByProps("useStateFromStores"),Re=s.findByStoreName("GuildReadStateStore"),S=48,Z=16,dt=[{top:6,left:6},{top:6,right:6},{bottom:6,left:6},{bottom:6,right:6}],Be=ce.getAssetIDByName("FolderIcon");function De(e){return e==null?"#5865f2":`#${e.toString(16).padStart(6,"0")}`}function ct({node:e}){const t=at?.useStateFromStores?.([Re],function(){let r=0;for(const i of e.children)r+=Re?.getMentionCount?.(i.id)??0;return r},[e.children])??0;return t>0?n.createElement(o.View,{style:N.outline},n.createElement(o.View,{style:N.badge},n.createElement(o.Text,{style:N.text},t>99?"99+":String(t)))):null}function ft({node:e}){X.useProxy(d.storage);const t=De(e.color);return n.createElement(o.View,{style:_.outer},n.createElement(o.View,{style:[_.icon,{backgroundColor:t}]},d.storage.hideFolderIcons?n.createElement(o.View,{style:_.plainIcon},n.createElement(o.Image,{source:Be,style:$.folderImg,tintColor:"#fff"})):e.children.slice(0,4).map(function(r,i){return n.createElement(o.View,{key:r.id,style:[_.cell,dt[i]]},n.createElement(fe,{id:r.id,size:Z}))})),n.createElement(ct,{node:e}))}const _=o.StyleSheet.create({outer:{width:S,height:S},icon:{width:S,height:S,borderRadius:16,overflow:"hidden"},cell:{position:"absolute",width:Z,height:Z,borderRadius:8,overflow:"hidden"},plainIcon:{width:S,height:S,alignItems:"center",justifyContent:"center"}});function ht({children:e}){const t=n.useRef(new o.Animated.Value(0)).current;return n.useEffect(function(){o.Animated.timing(t,{toValue:1,duration:180,useNativeDriver:!0}).start()},[]),n.createElement(o.Animated.View,{style:{opacity:t}},e)}function pt({node:e,onPick:t}){const r=lt(e.id),i=function(){ut?.toggleGuildFolderExpand?.(e.id)};return r?n.createElement(n.Fragment,null,n.createElement(o.Pressable,{onPress:i},n.createElement(o.View,{style:[$.openIcon,{backgroundColor:De(e.color)}]},n.createElement(o.Image,{source:Be,style:$.folderImg,tintColor:"#fff"}))),e.children.map(function(l){return n.createElement(ht,{key:l.id},n.createElement(Se,{node:l,onPick:t}))})):n.createElement(o.Pressable,{onPress:i},n.createElement(ft,{node:e}))}const $=o.StyleSheet.create({openIcon:{width:S,height:S,borderRadius:16,alignItems:"center",justifyContent:"center"},folderImg:{width:24,height:24}}),N=o.StyleSheet.create({outline:{position:"absolute",bottom:-3,right:-3,minWidth:23,minHeight:23,borderRadius:12,backgroundColor:"#1a1a2e",alignItems:"center",justifyContent:"center"},badge:{minWidth:19,height:19,borderRadius:9,backgroundColor:"#ed4245",alignItems:"center",justifyContent:"center",paddingHorizontal:5},text:{color:"#fff",fontSize:10,fontWeight:"700",lineHeight:19}}),gt=s.findByProps("useStateFromStores"),Ie=s.findByStoreName("SortedGuildStore"),yt=s.findByProps("getRootNavigationRef"),W=s.findByProps("triggerHapticFeedback","HapticFeedbackTypes"),Pe=s.findByProps("transitionToGuild"),mt=s.find(function(e){return typeof e?.handleCreateJoinGuildPress=="function"}),Fe=s.find(function(e){return e?.CirclePlusIcon})?.CirclePlusIcon,xe=s.findByProps("colors","unsafe_rawColors")?.unsafe_rawColors,bt=xe?.GREEN_360,Ae=xe?.WHITE,Et=s.find(function(e){return e?.QuestDockExternalCoordinationContext}),Ge=Et?.QuestDockExternalCoordinationContext,Te=s.find(function(e){return e?.QuestDockMode?.COLLAPSED!=null})?.QuestDockMode,j=48,v=6,Ct=12;function St(){const e=n.useRef(new o.Animated.Value(1)).current,t=n.useCallback(function(){o.Animated.spring(e,{toValue:.9,useNativeDriver:!0}).start()},[e]),r=n.useCallback(function(){o.Animated.spring(e,{toValue:1,useNativeDriver:!0}).start()},[e]),i=n.useCallback(function(){W?.triggerHapticFeedback?.(W.HapticFeedbackTypes.SOFT),mt?.handleCreateJoinGuildPress?.()},[]);return n.createElement(o.Pressable,{onPress:i,onPressIn:t,onPressOut:r},n.createElement(o.Animated.View,{style:[U.createJoin,{transform:[{scale:e}]}]},Fe?n.createElement(Fe,{size:"md",color:Ae}):n.createElement(o.Text,{style:U.createJoinFallback},"+")))}function Ve({gestureContext:e}){const t=n.useCallback(function(a){W?.triggerHapticFeedback(W.HapticFeedbackTypes.SOFT),Pe?.transitionToGuild?Pe.transitionToGuild(a,null):yt?.getRootNavigationRef()?.navigate("guilds",{guildId:a})},[]),r=gt?.useStateFromStores?.([Ie],function(){return(Ie?.getGuildsTree()?.root?.children||[]).filter(function(a){return a.type!=="root"})})??[],i=e?n.useContext(e):null,l=i?.minExpandedContentHeight,c=n.useCallback(function(a){if(!l)return;const b=a.nativeEvent.layout.height;l.get()!==b&&l.set(b)},[l]),h=(Ge?n.useContext(Ge):null)?.setRestingQuestDockMode,k=i?.questDockWrapperSpecs;n.useEffect(function(){if(!h||!Te||!k)return;const a=o.BackHandler.addEventListener("hardwareBackPress",function(){return(k.get()?.height??56)>80?(h(Te.COLLAPSED),!0):!1});return function(){return a.remove()}},[h,k]);const{width:R}=o.Dimensions.get("window"),m=Math.max(3,Math.floor((R-Ct*2+v)/(j+v))),g=m*j+(m-1)*v,B=Math.max(0,(R-g)/2);return n.createElement(o.View,{style:U.alignTop},n.createElement(o.View,{style:[U.grid,{paddingHorizontal:B,gap:v}],onLayout:c},r.map(function(a){return a.type==="folder"?n.createElement(pt,{key:a.id,node:a,onPick:t}):n.createElement(Se,{key:a.id,node:a,onPick:t})}),n.createElement(St,null)))}const U=o.StyleSheet.create({alignTop:{flex:1,justifyContent:"flex-start",alignItems:"flex-start"},grid:{flexDirection:"row",flexWrap:"wrap",paddingTop:4,paddingBottom:16},createJoin:{width:j,height:j,borderRadius:16,backgroundColor:bt,alignItems:"center",justifyContent:"center"},createJoinFallback:{color:Ae,fontSize:28,fontWeight:"700",lineHeight:30}}),ee=new Map;let w=null,z=!1;function He(e,t,r){ee.set(e,{replacement:t,extraProps:r})}function wt(e){if(z)return;if(w=u.React.createElement,!w){console.warn("[ServerDrawer] React.createElement is null, skipping patch");return}const t=function(r,i,...l){if(!w)return u.React.createElement(r,i,...l);const c=ee.get(r);if(c){const h=c.extraProps?{...i,...c.extraProps}:i;return w.call(u.React,c.replacement,h,...l)}return w.call(u.React,r,i,...l)};Object.assign(t,w),u.React.createElement=t,z=!0,e.push(function(){z&&w&&(u.React.createElement=w,z=!1),ee.clear()})}const te="[ServerDrawer]";let ne=null;function Qe(){return ne||(ne=s.find(function(e){return e?.QuestDockGestureContext})?.QuestDockGestureContext??null),ne}function kt(e){const t=s.find(function(i){return i?.type?.displayName==="QuestDockContentExpanded"||i?.type?.name==="QuestDockContentExpanded"});if(!t?.type)return console.log(te,"WARN: QuestDockContentExpanded not found (will retry)"),!1;const r=t.type;return He(r,Ve,{gestureContext:Qe()}),t.type=function(){return u.React.createElement(Ve,{gestureContext:Qe()})},e.push(function(){t.type=r}),console.log(te,"PATCH: QuestDockContentExpanded replaced"),!0}function A(e,t){const r=s.find(function(c){return c?.type?.displayName===e||c?.type?.name===e});if(!r?.type)return console.log(te,`WARN: ${e} not found`),!1;const i=r.type,l=i;return r.type=function(){return null},l&&(Object.defineProperties(r.type,Object.getOwnPropertyDescriptors(l)),r.type.displayName=e),t.push(function(){r.type=i}),!0}const Rt="[ServerDrawer]",Bt=ce.getAssetIDByName("ChatIcon"),Me=s.findByProps("triggerHapticFeedback","HapticFeedbackTypes"),Le=s.findByProps("selectPrivateChannel"),Dt=s.findByName("SelectedChannelStore"),It=s.findByProps("useStateFromStores"),Pt=It?.useStateFromStores,oe=s.findByProps("getGuildId"),re=s.findByProps("colors","unsafe_rawColors")?.colors,Ft=s.findByProps("ME"),xt=Ft?.ME??"/channels/@me";function At(){if(Me?.triggerHapticFeedback(Me.HapticFeedbackTypes.SOFT),Le?.selectPrivateChannel){const e=Dt?.getLastSelectedChannelId?.();Le.selectPrivateChannel(e)}}function Gt(){try{return oe?Pt([oe],function(){const e=oe?.getGuildId?.();return e==null||e===xt}):!1}catch{return!1}}function Oe(){const e=Gt(),t=e?re?.WHITE??"#fff":re?.INTERACTIVE_NORMAL??"#80848e";return n.createElement(o.Pressable,{onPress:At,style:{flex:1,alignItems:"center",justifyContent:"center"}},e?n.createElement(o.View,{style:{position:"absolute",left:0,top:"25%",width:4,height:"50%",borderRadius:2,backgroundColor:re?.WHITE??"#fff"}}):null,n.createElement(o.Image,{source:Bt,style:{width:28,height:28,tintColor:t}}))}function Tt(){const e=s.findByName("GuildsBar");if(e)return{default:e};let t=s.find(function(r){try{return r?.default?.type?.name==="GuildsBar"}catch{return!1}});return t?.default||(t=s.find(function(r){try{return r?.default?.displayName==="GuildsBar"}catch{return!1}}),t?.default)?t:null}function Vt(e){const t=Tt();if(!t?.default)return console.log(Rt,"WARN: GuildsBar not found"),!1;const r=t.default;return He(r,Oe),t.default=function(){return n.createElement(Oe)},t.default.displayName="GuildsBar",e.push(function(){t.default=r}),!0}function Ht(e){const t=s.findByStoreName("ExpandedGuildFolderStore");if(!t?.getExpandedFolders)return!1;const r=function({folderId:i}){if(!d.storage.autoCollapseFolders||i==null)return;const l=t.getExpandedFolders();if(!(!(l instanceof Set)||!l.has(i)))for(const c of l)c!==i&&u.FluxDispatcher.dispatch({type:"TOGGLE_GUILD_FOLDER_EXPAND",folderId:c})};return u.FluxDispatcher.subscribe("TOGGLE_GUILD_FOLDER_EXPAND",r),e.push(function(){return u.FluxDispatcher.unsubscribe("TOGGLE_GUILD_FOLDER_EXPAND",r)}),!0}const{ScrollView:Qt,View:Mt}=u.ReactNative;function Lt({children:e}){return u.React.createElement(Qt,{style:{flex:1}},e,u.React.createElement(Mt,{style:{height:24}}))}const{View:Ot,Text:_t}=u.ReactNative;function _e({children:e,style:t}){return u.React.createElement(Ot,{style:[{marginHorizontal:16,marginVertical:8,padding:10,borderRadius:8,borderWidth:1,borderColor:"rgba(128,128,128,0.25)"},t]},u.React.createElement(_t,{style:{fontSize:12.5,lineHeight:18,opacity:.75}},e))}const{FormSection:We,FormSwitchRow:q}=ze.Forms;function Wt(){return X.useProxy(d.storage),u.React.createElement(Lt,null,u.React.createElement(_e,null,"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 use the + button to create or join a server through Discord's own modal."),u.React.createElement(We,{title:"Layout"},u.React.createElement(q,{label:"Hide the left server rail",subLabel:"Replaces it with a single DMs icon since your servers now live in the drawer",value:d.storage.hideGuildsBar!==!1,onValueChange:function(e){d.storage.hideGuildsBar=e,Ue()}}),u.React.createElement(q,{label:"Unread badges",subLabel:"Show mention counts and unread dots on server icons in the drawer",value:d.storage.showUnreadBadges!==!1,onValueChange:function(e){d.storage.showUnreadBadges=e}})),u.React.createElement(We,{title:"Folders"},u.React.createElement(q,{label:"Auto-collapse other folders",subLabel:"Opening a folder collapses any other folder that was already open",value:!!d.storage.autoCollapseFolders,onValueChange:function(e){d.storage.autoCollapseFolders=e}}),u.React.createElement(q,{label:"Hide icons in collapsed folders",subLabel:"Show a plain folder icon instead of a 4-server preview",value:!!d.storage.hideFolderIcons,onValueChange:function(e){d.storage.hideFolderIcons=e}})),u.React.createElement(_e,null,"The folder options above are ported from fres621's BetterFolders - its other half (hiding icons in the native left server rail) patched a component that no longer exists in current Discord builds, so it's been rebuilt here instead, where it actually applies to what you see."))}let f=[];function p(e,t){try{return t()}catch(r){return de.logger.error(`[ServerDrawer] "${e}" patch threw, skipping: ${r}`),!1}}function je(){const e=[];wt(f),p("questDockRender",function(){return qe(f)})&&e.push("questDockRender"),p("questDockBase",function(){return Xe(f)})&&e.push("questDockBase"),p("mobileQuestDock",function(){return Je(f)})&&e.push("mobileQuestDock"),p("getQuestAsset",function(){return Ye(f)})&&e.push("getQuestAsset"),p("expanded",function(){return kt(f)})&&e.push("expanded"),p("collapsed",function(){return A("QuestDockContentCollapsed",f)})&&e.push("collapsed"),p("enrolledHeader",function(){return A("QuestDockEnrolledHeader",f)})&&e.push("enrolledHeader"),p("unenrolledHeader",function(){return A("QuestDockUnenrolledHeader",f)})&&e.push("unenrolledHeader"),p("enrolledBody",function(){return A("QuestDockEnrolledBody",f)})&&e.push("enrolledBody"),p("unenrolledBody",function(){return A("QuestDockUnenrolledBody",f)})&&e.push("unenrolledBody"),d.storage.hideGuildsBar&&p("hideGuildsBar",function(){return Vt(f)})&&e.push("hideGuildsBar"),p("autoCollapseFolders",function(){return Ht(f)})&&e.push("autoCollapseFolders"),de.logger.log(`[ServerDrawer] onLoad done - ${e.length}/12 patches applied (${e.join(", ")||"none"})`)}function ve(){for(const e of f)try{e()}catch{}f=[]}function Ue(){ve(),je()}var jt={onLoad:function(){d.storage.hideGuildsBar??=!0,d.storage.showUnreadBadges??=!0,d.storage.autoCollapseFolders??=!1,d.storage.hideFolderIcons??=!1,je()},onUnload:function(){return ve()},settings:Wt};return V.default=jt,V.restart=Ue,Object.defineProperty(V,"__esModule",{value:!0}),V})({},vendetta,vendetta.plugin,vendetta.metro,vendetta.metro.common,window.React,vendetta.metro.common.ReactNative,vendetta.storage,vendetta.ui,vendetta.ui.assets,vendetta.ui.components); diff --git a/server-drawer/install/manifest.json b/server-drawer/install/manifest.json index 1b66d07..23a8ede 100644 --- a/server-drawer/install/manifest.json +++ b/server-drawer/install/manifest.json @@ -1 +1 @@ -{"name":"ServerDrawer","description":"Replaces the Quest Dock with a server grid drawer above the YouBar - tap to expand, long-press a server for its context menu, plus a one-tap create/join button.","authors":[{"name":"everestmcarthur"},{"name":"kmmiio99o"}],"main":"index.js","vendetta":{"icon":"ServerIcon"},"hash":"2254b8b66310e9b63158997b9c661cfa1a9971f762e8b9578bf312f472076a4e"} \ No newline at end of file +{"name":"ServerDrawer","description":"Replaces the Quest Dock with a server grid drawer above the YouBar - tap to expand, long-press a server for its context menu, plus a one-tap create/join button.","authors":[{"name":"everestmcarthur"},{"name":"kmmiio99o"},{"name":"fres"}],"main":"index.js","vendetta":{"icon":"ServerIcon"},"hash":"16050115ca69a6df56c2ba681967b0a113ea2f9bb6ff911431a97493d8223d75"} \ No newline at end of file