diff --git a/view-raw/install/index.js b/view-raw/install/index.js index 0de2bd5..cc598ce 100644 --- a/view-raw/install/index.js +++ b/view-raw/install/index.js @@ -1,2 +1,2 @@ -(function(w,P,p,E,s,e,h,S,x){"use strict";function m(t){const n=JSON.parse(JSON.stringify(t));for(const r in n.author)switch(r){case"email":case"phone":case"mfaEnabled":case"hasBouncedEmail":delete n.author[r]}return n}const{View:_,Text:B}=e.ReactNative,l={key:"#7dd3fc",string:"#86efac",number:"#fbbf24",boolean:"#c4b5fd",null:"#9ca3af",punct:"#d1d5db"},F=/^(\s*)("(?:[^"\\]|\\.)*"\s*:\s*)?(.*)$/;function L(t){return t.startsWith('"')?l.string:/^(true|false)/.test(t)?l.boolean:/^null/.test(t)?l.null:/^-?\d/.test(t)?l.number:l.punct}function O({text:t,query:n}){const r=e.React.useMemo(function(){return t.split(` -`)},[t]),i=(n||"").trim().toLowerCase();return e.React.createElement(_,null,r.map(function(d,A){const R=d.match(F),y=R?.[1]??"",o=R?.[2],f=R?.[3]??d,c=!!i&&d.toLowerCase().includes(i),b=!!i&&!c;return e.React.createElement(B,{key:A,selectable:!0,style:{fontFamily:"monospace",fontSize:12.5,lineHeight:18,opacity:b?.35:1,backgroundColor:c?"rgba(88,101,242,0.25)":"transparent"}},y,o?e.React.createElement(B,{style:{color:l.key}},o):null,e.React.createElement(B,{style:{color:L(f)}},f))}))}const{View:z,ScrollView:T,TextInput:H,Text:v}=e.ReactNative;function W({message:t}){const[n,r]=e.React.useState(""),i=e.React.useMemo(function(){return JSON.stringify(m(t),null,4)},[t.id]);return e.React.createElement(T,{style:{flex:1,marginHorizontal:13,marginVertical:10}},e.React.createElement(z,{style:{flexDirection:"row"}},e.React.createElement(h.Button,{style:{flex:1,marginRight:8,marginBottom:8},text:"Copy Content",color:"brand",size:"small",disabled:!t.content,onPress:function(){e.clipboard.setString(t.content),S.showToast("Copied content to clipboard",p.getAssetIDByName("toast_copy_link"))}}),e.React.createElement(h.Button,{style:{flex:1,marginBottom:8},text:"Copy JSON",color:"brand",size:"small",onPress:function(){e.clipboard.setString(i),S.showToast("Copied JSON to clipboard",p.getAssetIDByName("toast_copy_link"))}})),e.React.createElement(H,{value:n,onChangeText:r,placeholder:"Search keys or values\u2026",placeholderTextColor:"#888",autoCapitalize:"none",autoCorrect:!1,style:{borderWidth:1,borderColor:"rgba(128,128,128,0.35)",borderRadius:8,paddingHorizontal:10,paddingVertical:8,marginBottom:10,color:"#fff"}}),!!t.content&&e.React.createElement(z,{style:{marginBottom:12}},e.React.createElement(v,{style:{fontSize:11,opacity:.6,marginBottom:4,fontWeight:"700"}},"MESSAGE CONTENT"),e.React.createElement(v,{selectable:!0,style:{fontFamily:"monospace",fontSize:13}},t.content)),e.React.createElement(v,{style:{fontSize:11,opacity:.6,marginBottom:4,fontWeight:"700"}},"RAW DATA"),e.React.createElement(T,{horizontal:!0,showsHorizontalScrollIndicator:!0},e.React.createElement(O,{text:i,query:n})))}function u(t,n=""){x.storage.lastDetection={strategy:t,detail:n,timestamp:Date.now()}}function J(){return x.storage.lastDetection}const{ScrollView:M,View:q}=e.ReactNative;function G({children:t}){return e.React.createElement(M,{style:{flex:1}},t,e.React.createElement(q,{style:{height:24}}))}const{View:j,Text:U}=e.ReactNative;function V({children:t,style:n}){return e.React.createElement(j,{style:[{marginHorizontal:16,marginVertical:8,padding:10,borderRadius:8,borderWidth:1,borderColor:"rgba(128,128,128,0.25)"},n]},e.React.createElement(U,{style:{fontSize:12.5,lineHeight:18,opacity:.75}},t))}const{TouchableOpacity:K,Text:Q}=e.ReactNative;function X({label:t,onPress:n,disabled:r,style:i}){return e.React.createElement(K,{disabled:r,onPress:n,style:[{backgroundColor:"#5865F2",borderRadius:8,padding:10,alignItems:"center",opacity:r?.5:1},i]},e.React.createElement(Q,{style:{color:"white",fontWeight:"600"}},t))}const{FormSection:Y,FormRow:Z}=h.Forms,ee={buttons:"Strategy 1 (button list) - working normally",actionSheetRow:"Strategy 2 (row group) - working normally",generic:"Strategy 3 (generic fallback) - the primary two shapes didn't match on this Discord build, but a broader fallback found a spot anyway",none:"None matched - the button couldn't be added on this Discord build"};function te(){const t=J();return e.React.createElement(G,null,e.React.createElement(Y,{title:"Diagnostics"},t?e.React.createElement(Z,{label:ee[t.strategy]??t.strategy,subLabel:`Last checked ${new Date(t.timestamp).toLocaleString()}${t.detail?` - ${t.detail}`:""}`}):e.React.createElement(V,null,"No data yet - long-press any message once, then come back here."),e.React.createElement(X,{style:{marginHorizontal:16,marginTop:8},label:"Copy diagnostics",disabled:!t,onPress:function(){e.clipboard.setString(JSON.stringify(t,null,2)),S.showToast("Copied - paste this if you're reporting an issue",void 0)}})),e.React.createElement(V,null,`"View Raw" is added to the message long-press menu by detecting Discord's internal action-sheet layout, which isn't an official API and can change between app versions. If it stops appearing for you, open this page after long-pressing a message and copy the diagnostics into a bug report - it'll say exactly which detection strategy ran.`))}const C=s.findByProps("openLazy","hideActionSheet"),N=s.findByProps("push","pushLazy","pop"),ne=s.findByProps("getRenderCloseButton")?.getRenderCloseButton??s.findByProps("getHeaderCloseButton")?.getHeaderCloseButton,ae=s.findByName("Navigator")??s.findByProps("Navigator")?.Navigator,{FormRow:re,FormIcon:$}=h.Forms;function D(t){return e.React.createElement(re,{label:"View Raw",leading:e.React.createElement($,{style:{opacity:1},source:p.getAssetIDByName("ic_chat_bubble_16px")}),onPress:function(){C.hideActionSheet(),N.push(t)}})}const ie=P.before("openLazy",C,function([t,n,r]){const i=r?.message;n!=="MessageLongPressActionSheet"||!i||t.then(function(d){const A=P.after("default",d,function(R,y){e.React.useEffect(function(){return function(){A()}},[]);try{const o=function(){return e.React.createElement(ae,{initialRouteName:"RawPage",goBackOnBackPress:!0,screens:{RawPage:{title:"ViewRaw",headerLeft:ne?.(function(){return N.pop()}),render:function(){return e.React.createElement(W,{message:i})}}}})},f=E.findInReactTree(y,function(a){return a?.[0]?.type?.name==="ButtonRow"}),c=E.findInReactTree(y,function(a){return Array.isArray(a)&&a[0]?.type?.name==="ActionSheetRowGroup"});if(f){f.push(D(o)),u("buttons");return}if(c&&c[1]){const a=c[1],g=a?.props?.children?.[0],I=g?.type,k=g?.props?.icon;if(I&&k&&Array.isArray(a?.props?.children)){const se=e.React.createElement(I,{label:"View Raw",icon:{$$typeof:k.$$typeof,type:k.type,key:null,ref:null,props:{IconComponent:function(){return e.React.createElement($,{style:{opacity:1},source:p.getAssetIDByName("ic_chat_bubble_32px")})}}},onPress:function(){C.hideActionSheet(),N.push(o)},key:"view-raw"});a.props.children.push(se),u("actionSheetRow");return}}const b=E.findInReactTree(y,function(a){return Array.isArray(a)&&a.length>0&&a.every(function(g){return typeof g?.props?.label=="string"&&typeof g?.props?.onPress=="function"})});if(Array.isArray(b)){b.push(D(o)),u("generic");return}console.log("[ViewRaw] Error: Could not find ActionSheet"),u("none")}catch(o){console.log("[ViewRaw] Error: Failed to add View Raw button",o),u("none",String(o))}})})});var oe={onUnload:function(){return ie()},settings:te};return w.default=oe,Object.defineProperty(w,"__esModule",{value:!0}),w})({},vendetta.patcher,vendetta.ui.assets,vendetta.utils,vendetta.metro,vendetta.metro.common,vendetta.ui.components,vendetta.ui.toasts,vendetta.plugin); +(function(E,N,R,b,c,e,w,S,P){"use strict";function F(t){const n=JSON.parse(JSON.stringify(t));for(const i in n.author)switch(i){case"email":case"phone":case"mfaEnabled":case"hasBouncedEmail":delete n.author[i]}return n}const{View:L,Text:v}=e.ReactNative,d={key:"#7dd3fc",string:"#86efac",number:"#fbbf24",boolean:"#c4b5fd",null:"#9ca3af",punct:"#d1d5db"},O=/^(\s*)("(?:[^"\\]|\\.)*"\s*:\s*)?(.*)$/;function H(t){return t.startsWith('"')?d.string:/^(true|false)/.test(t)?d.boolean:/^null/.test(t)?d.null:/^-?\d/.test(t)?d.number:d.punct}function M({text:t,query:n}){const i=e.React.useMemo(function(){return t.split(` +`)},[t]),a=(n||"").trim().toLowerCase();return e.React.createElement(L,null,i.map(function(y,I){const l=y.match(O),o=l?.[1]??"",p=l?.[2],s=l?.[3]??y,h=!!a&&y.toLowerCase().includes(a),r=!!a&&!h;return e.React.createElement(v,{key:I,selectable:!0,style:{fontFamily:"monospace",fontSize:12.5,lineHeight:18,opacity:r?.35:1,backgroundColor:h?"rgba(88,101,242,0.25)":"transparent"}},o,p?e.React.createElement(v,{style:{color:d.key}},p):null,e.React.createElement(v,{style:{color:H(s)}},s))}))}const{View:C,ScrollView:_,TextInput:W,Text:A}=e.ReactNative;function J({message:t}){const[n,i]=e.React.useState(""),a=e.React.useMemo(function(){return JSON.stringify(F(t),null,4)},[t.id]);return e.React.createElement(_,{style:{flex:1,marginHorizontal:13,marginVertical:10}},e.React.createElement(C,{style:{flexDirection:"row"}},e.React.createElement(w.Button,{style:{flex:1,marginRight:8,marginBottom:8},text:"Copy Content",color:"brand",size:"small",disabled:!t.content,onPress:function(){e.clipboard.setString(t.content),S.showToast("Copied content to clipboard",R.getAssetIDByName("toast_copy_link"))}}),e.React.createElement(w.Button,{style:{flex:1,marginBottom:8},text:"Copy JSON",color:"brand",size:"small",onPress:function(){e.clipboard.setString(a),S.showToast("Copied JSON to clipboard",R.getAssetIDByName("toast_copy_link"))}})),e.React.createElement(W,{value:n,onChangeText:i,placeholder:"Search keys or values\u2026",placeholderTextColor:"#888",autoCapitalize:"none",autoCorrect:!1,style:{borderWidth:1,borderColor:"rgba(128,128,128,0.35)",borderRadius:8,paddingHorizontal:10,paddingVertical:8,marginBottom:10,color:"#fff"}}),!!t.content&&e.React.createElement(C,{style:{marginBottom:12}},e.React.createElement(A,{style:{fontSize:11,opacity:.6,marginBottom:4,fontWeight:"700"}},"MESSAGE CONTENT"),e.React.createElement(A,{selectable:!0,style:{fontFamily:"monospace",fontSize:13}},t.content)),e.React.createElement(A,{style:{fontSize:11,opacity:.6,marginBottom:4,fontWeight:"700"}},"RAW DATA"),e.React.createElement(_,{horizontal:!0,showsHorizontalScrollIndicator:!0},e.React.createElement(M,{text:a,query:n})))}function f(t,n=""){P.storage.lastDetection={strategy:t,detail:n,timestamp:Date.now()}}function G(){return P.storage.lastDetection}const{ScrollView:q,View:j}=e.ReactNative;function U({children:t}){return e.React.createElement(q,{style:{flex:1}},t,e.React.createElement(j,{style:{height:24}}))}const{View:K,Text:Q}=e.ReactNative;function T({children:t,style:n}){return e.React.createElement(K,{style:[{marginHorizontal:16,marginVertical:8,padding:10,borderRadius:8,borderWidth:1,borderColor:"rgba(128,128,128,0.25)"},n]},e.React.createElement(Q,{style:{fontSize:12.5,lineHeight:18,opacity:.75}},t))}const{TouchableOpacity:X,Text:Y}=e.ReactNative;function Z({label:t,onPress:n,disabled:i,style:a}){return e.React.createElement(X,{disabled:i,onPress:n,style:[{backgroundColor:"#5865F2",borderRadius:8,padding:10,alignItems:"center",opacity:i?.5:1},a]},e.React.createElement(Y,{style:{color:"white",fontWeight:"600"}},t))}const{FormSection:ee,FormRow:te}=w.Forms,ne={buttons:"Strategy 1 (button list) - working normally",actionSheetRow:"Strategy 2 (row group) - working normally",generic:"Strategy 3 (generic fallback) - the primary two shapes didn't match on this Discord build, but a broader fallback found a spot anyway",none:"None matched - the button couldn't be added on this Discord build"};function ae(){const t=G();return e.React.createElement(U,null,e.React.createElement(ee,{title:"Diagnostics"},t?e.React.createElement(te,{label:ne[t.strategy]??t.strategy,subLabel:`Last checked ${new Date(t.timestamp).toLocaleString()}${t.detail?` - ${t.detail}`:""}`}):e.React.createElement(T,null,"No data yet - long-press any message once, then come back here."),e.React.createElement(Z,{style:{marginHorizontal:16,marginTop:8},label:"Copy diagnostics",disabled:!t,onPress:function(){e.clipboard.setString(JSON.stringify(t,null,2)),S.showToast("Copied - paste this if you're reporting an issue",void 0)}})),e.React.createElement(T,null,`"View Raw" is added to the message long-press menu by detecting Discord's internal action-sheet layout, which isn't an official API and can change between app versions. If it stops appearing for you, open this page after long-pressing a message and copy the diagnostics into a bug report - it'll say exactly which detection strategy ran.`))}const k=c.findByProps("openLazy","hideActionSheet"),x=c.findByProps("push","pushLazy","pop"),re=c.findByProps("getRenderCloseButton")?.getRenderCloseButton??c.findByProps("getHeaderCloseButton")?.getHeaderCloseButton,z=c.findByName("Navigator")??c.findByProps("Navigator")?.Navigator,{ActionSheetRow:g}=c.findByProps("ActionSheetRow")??{},{FormRow:ie,FormIcon:oe}=w.Forms;function se(t){return function(){return e.React.createElement(z,{initialRouteName:"RawPage",goBackOnBackPress:!0,screens:{RawPage:{title:"ViewRaw",headerLeft:re?.(function(){return x.pop()}),render:function(){return e.React.createElement(J,{message:t()})}}}})}}function D(t){k.hideActionSheet(),x.push(t)}function V(t){return e.React.createElement(ie,{label:"View Raw",leading:e.React.createElement(oe,{style:{opacity:1},source:R.getAssetIDByName("ic_chat_bubble_16px")}),onPress:function(){return D(t)}})}function ce(t){return e.React.createElement(g,{label:"View Raw",icon:e.React.createElement(g.Icon,{source:R.getAssetIDByName("ic_chat_bubble_16px")}),onPress:function(){return D(t)},key:"view-raw"})}const B=[],le=N.before("openLazy",k,function([t,n,i]){n!=="MessageLongPressActionSheet"||!i?.message||t.then(function(a){if(a.__viewRawActiveMessage=i.message,a.__viewRawPatched)return;a.__viewRawPatched=!0;const y=N.after("default",a,function(I,l){try{if(!z){console.log("[ViewRaw] Error: Navigator not found - can't open RawPage"),f("none","Navigator not found");return}const o=se(function(){return a.__viewRawActiveMessage}),p=b.findInReactTree(l,function(r){return r?.[0]?.type?.name==="ButtonRow"});if(p){p.push(V(o)),f("buttons");return}const s=b.findInReactTree(l,function(r){return Array.isArray(r)&&r[0]?.type?.name==="ActionSheetRowGroup"});if(Array.isArray(s)&&s.length&&g){const r=ce(o);let u=!1;for(const de of s){const m=b.findInReactTree(de,function($){return Array.isArray($)&&$.some(function(fe){return fe?.type?.name==="ActionSheetRow"})});if(Array.isArray(m)){m.push(r),u=!0;break}}if(!u&&typeof s.unshift=="function"&&g.Group&&(s.unshift(e.React.createElement(g.Group,null,r)),u=!0),u){f("actionSheetRow");return}}const h=b.findInReactTree(l,function(r){return Array.isArray(r)&&r.length>0&&r.every(function(u){return typeof u?.props?.label=="string"&&typeof u?.props?.onPress=="function"})});if(Array.isArray(h)){h.push(V(o)),f("generic");return}console.log("[ViewRaw] Error: Could not find ActionSheet"),f("none")}catch(o){console.log("[ViewRaw] Error: Failed to add View Raw button",o),f("none",String(o))}});B.push(y)})});B.push(le);var ue={onUnload:function(){return B.forEach(function(t){return t()})},settings:ae};return E.default=ue,Object.defineProperty(E,"__esModule",{value:!0}),E})({},vendetta.patcher,vendetta.ui.assets,vendetta.utils,vendetta.metro,vendetta.metro.common,vendetta.ui.components,vendetta.ui.toasts,vendetta.plugin); diff --git a/view-raw/install/manifest.json b/view-raw/install/manifest.json index 797d544..2511367 100644 --- a/view-raw/install/manifest.json +++ b/view-raw/install/manifest.json @@ -1 +1 @@ -{"name":"ViewRaw","description":"View a message's raw JSON data - searchable, syntax-highlighted, and copyable. Fork of bwlok's ViewRaw with a crash fix and a nicer viewer.","authors":[{"name":"everestmcarthur"},{"name":"sapphire"},{"name":"Vendicated"},{"name":"Bwlok"}],"main":"index.js","hash":"486cf24f3bb9d609a54bc5ae9ca6b3a0ba1d73dd08ee33a7a64da37f3bbc7305"} \ No newline at end of file +{"name":"ViewRaw","description":"View a message's raw JSON data - searchable, syntax-highlighted, and copyable. Fork of bwlok's ViewRaw with a crash fix and a nicer viewer.","authors":[{"name":"everestmcarthur"},{"name":"sapphire"},{"name":"Vendicated"},{"name":"Bwlok"}],"main":"index.js","hash":"1701eb68434d4a11ccdc4552eb23eb32795982f277d630ca21bda371fd0f4d5e"} \ No newline at end of file